没有ListBox.SelectionMode =“ None”,还有另一种方法来禁用列表框中的选择吗?


189

如何禁用列表框中的选择?


1
您能否提供一个示例,其中包含一个不能从中选择的ListBox是有效的?由于主要行为是选择项目。我可能会选择另一种显示方式。(这不是我要成为评论家,而是对可能发生这种情况的真正兴趣)
Marthin 2012年

3
@Martin:例如,如果您想从列表框项目中拖动内容,在这种情况下,您可能不希望选择该项目。还:拖动项目时:在列表
框内

1
我相信Shimmy想要使用ListBox的原因是,询问者可以在某个时候使列表框成为可选择的。这个问题对我也很重要。假设您正在构建纸牌游戏。您可以从卡中选择一张,有时可以选择多个,而在其他时间则不能选择。
Gqqnbig

1
另外,有时您有10张卡,其中只有4张是可选的。其中4,您最多可以选择3
Gqqnbig

1
@Marthin:当您在ListBox中具有GridView时。Gridview标头提供了许多其他地方没有的功能。您在gridview的单元格中具有编辑控件。
罗宾·戴维斯

Answers:


264

方法1- ItemsControl

除非需要的其他方面,否则ListBox可以使用ItemsControl。它将项目放置在中,ItemsPanel并且没有选择的概念。

<ItemsControl ItemsSource="{Binding MyItems}" />

默认情况下,ItemsControl不支持对其子元素进行虚拟化。如果您有很多东西,虚拟化可以减少内存使用并提高性能,在这种情况下,您可以使用方法2并设置样式ListBox向中添加虚拟化ItemsControl

方法2-样式 ListBox

或者,只需设置ListBox的样式,使选择不可见。

<ListBox.Resources>
  <Style TargetType="ListBoxItem">
    <Style.Resources>
      <!-- SelectedItem with focus -->
      <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                       Color="Transparent" />
      <!-- SelectedItem without focus -->
      <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
                       Color="Transparent" />
      <!-- SelectedItem text foreground -->
      <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}"
                       Color="Black" />
    </Style.Resources>
    <Setter Property="FocusVisualStyle" Value="{x:Null}" />
  </Style>
</ListBox.Resources>

24
不,它只会改变视觉效果,而不会改变实际的选择行为
Thomas Levesque 2009年

8
我的第一个建议是使用ItemsControl。你想念吗?:)
Drew Noakes

5
我要再次阅读这些评论,我想指出@Thomas Levesque的评论仅适用于我展示的第二种方法。使用plain ItemsControl将完全删除任何选择概念。
Drew Noakes

1
ItemsControl解决方案取消了框滚动支持(滚动条和鼠标滚轮)。
MuiBienCarlota

1
为方法1-ItemsControl +1。如果我们有一个很大的页面需要滚动,如果用户将鼠标悬停在ListBox上,则当列表框捕获MouseWheel事件时,它将有效地禁用MouseWheel。这意味着用户会感到沮丧,用于滚动整个页面的鼠标滚轮将随机停止工作,具体取决于鼠标是否位于列表框上方。
2015年

159

我找到了一个非常简单直接的解决方案为我工作,我希望它也对您有用

<ListBox ItemsSource="{Items}">
    <ListBox.ItemContainerStyle>
       <Style TargetType="{x:Type ListBoxItem}">
           <Setter Property="Focusable" Value="False"/>
       </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

我认为他在这里做得
Sid

3
太棒了。它会阻止所选项目,并且其他控件(如按钮)仍然有效。正是我在寻找什么
Franck

1
为此方法+1。如果我们有一个很大的页面需要滚动,如果用户将鼠标悬停在ListBox上,则当列表框捕获MouseWheel事件时,它将有效地禁用MouseWheel。这意味着用户会感到沮丧,用于滚动整个页面的鼠标滚轮将随机停止工作,具体取决于鼠标是否位于列表框上方。
2015年

优秀的。当我需要在项目上使用按钮而不引起项目选择时(但仅在单击项目的其他区域时),类似的方法也对我有用。只需设置按钮Focusable = "False"
乔尼

1
添加此附加属性也可以删除鼠标悬停突出显示: <Setter Property="IsHitTestVisible" Value="False" />
DonBoitnott

25

您可以改用ItemsControl而不是ListBox。An ItemsControl没有选择的概念,因此没有必要关闭。


2
迷人。我不知道您可以直接声明ItemsControl,我认为它是虚拟的(MustOverride),谢谢!!!
Shimmy Weitzhandler,2009年

但是ItemsControl仍将我的项目呈现在一行中吗?
Chry Cheng

@Chry是的,此外,您始终可以手动设置ItemTemplate
Shimmy Weitzhandler,2010年

2
最终会失去太多功能-例如滚动。
杰夫

@Jeff,您可以将ItemsControl包装在ScrollViewer中以进行滚动。
Wilka '02

12

另一个值得考虑的选项是禁用ListBoxItems。可以通过设置ItemContainerStyle来完成此操作,如以下代码片段所示。

<ListBox ItemsSource="{Binding YourCollection}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsEnabled" Value="False" />
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

如果您不希望文本为灰色,则可以通过使用以下键向样式的资源添加画笔来指定禁用的颜色:{x:Static SystemColors.GrayTextBrushKey}。另一种解决方案是重写ListBoxItem控件模板。


简单而有效,谢谢!它也适用于WP 8.1 Runtime。
Malutek

8

如果我需要使用列表框而不是itemscontrol,但是我只是显示不应选择的项目,这也可以使用:

<ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
        <Setter Property="IsHitTestVisible" Value="False" />
    </Style>
</ListBox.ItemContainerStyle>

3

这里给出了很好的答案,但是我正在寻找稍微不同的东西:我想要选择,但只是不想显示(或以其他方式显示)。

上面的解决方案对我不起作用(完全),因此我做了其他事情:我为列表框使用了一种新样式,它完全重新定义了模板:

<Style x:Key="PlainListBoxStyle" TargetType="ListBox">
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <ContentPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBox}">
                <ItemsPresenter/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

从此开始,您可以轻松地添加自己的选择突出显示,或者如果您根本不想要任何内容​​,则可以像这样保留它。


2

@Drew Noakes的答案是大多数情况下的快速解决方案,但是设置x:Static笔刷存在一些缺陷。

当按照建议设置x:Static笔刷时,列表框项目中的所有子控件都将继承此样式。

这意味着,尽管这将禁用列表框项目的突出显示,但可能会导致子控件产生不良效果。

例如,如果您的ListBoxItem中有一个ComboBox,它将使鼠标无法在ComboBox中突出显示。

相反,请考虑按照此stackoverflow线程中提到的解决方案中所述,为Selected,Unselected和MouseOver事件设置VisualStates:从ListBoxItem除去控件突出显示,而不是子控件

-弗林尼


2

我提出了另一种解决方案。只需重新模板ListBoxItem就可以了ContentPresenter,就像这样...

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <ContentPresenter />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我采用这种方法的原因如下:

  1. 就我而言,我不想禁用用户与我的内容的交互,ListBoxItems因此设置的解决方案IsEnabled对我不起作用。

  2. 另一个尝试ListBoxItem通过覆盖与颜色相关的属性来重新设置样式的解决方案仅适用于您确定模板使用这些属性的情况。默认样式很好,但是会与自定义样式一起破坏。

  3. 使用ItemsControl中断的解决方案会破坏很多其他事情,因为其ItemsControl外观与标准完全不同ListBox,并且不支持虚拟化,这意味着ItemsPanel无论如何您都必须重新模板化。

上面的内容不会更改的默认外观ListBox,不会禁用的数据模板中的项目ListBox,默认情况下支持虚拟化,并且可以独立于应用程序中可能使用或可能不使用的任何样式工作。这是KISS原则。


1

注意:此解决方案不会禁用通过键盘导航或右键单击的选择(即,箭头键后跟空格键)

先前的所有答案要么完全删除功能选择(在运行时不切换),要么仅删除视觉效果,但不删除选择。

但是,如果您希望能够通过代码而不是通过用户输入来选择和显示选择,该怎么办?可能是您想“冻结”用户的选择,同时又不禁用整个列表框?

解决方案是将整个ItemsContentTemplate包装到没有可见镶边的Button中。按钮的大小必须等于Item的大小,因此已完全覆盖。现在使用按钮的IsEnabled-Property:

启用按钮以“冻结”项目的选择状态。之所以有效,是因为已启用的按钮在所有鼠标事件冒泡到ListboxItem-Eventhandler之前就吃掉了它们。您的ItemsDataTemplate仍将接收MouseEvent,因为它是按钮内容的一部分。

禁用该按钮以启用通过单击更改选择。

<Style x:Key="LedCT" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Button IsEnabled="{Binding IsSelectable, Converter={StaticResource BoolOppositeConverter}}" Template="{DynamicResource InvisibleButton}">
                        <ContentPresenter />
                </Button>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<ControlTemplate x:Key="InvisibleButton" TargetType="{x:Type Button}">
    <ContentPresenter/>
</ControlTemplate>

达特拉克斯


1

也许您只需要ItemsControl的功能?它不允许选择:

<ItemsControl ItemsSource="{Binding Prop1}" ItemTemplate="{StaticResource DataItemsTemplate}" />

3
@Shimmy:平凡的答案通常是相似的。这里没有任何值得重复的标记。如果您对此还有其他疑问,请在Meta Stack Overflow上提问。

0

您可以在列表框上方放置一个Textblock,它不会改变应用程序的外观,也不允许选择任何项目。


1
不过,您仍然需要禁用标签导航。
阿曼杜

0

例如,一个适用于Windows Phone的简单修复程序是在将所选项目设置为null的选择上:

    <ListBox SelectionChanged="ListBox_SelectionChanged">

并在后面的代码中:

    private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        (sender as ListBox).SelectedItem = null;
    }

0

我找到了一个完美的方法。
将ListBox IsHitTestVisible设置为false,以使用户无法将鼠标悬停或向下滚动或向上滚动。
捕获PreviewGotKeyboardFocus e.Handled = true,以便用户可以通过键盘Tab,向上箭头,向下箭头选择项目。

这样优势:

  1. 列表框项目前景不会变为灰色。
  2. 列表框背景可以设置为透明

xmal

<ListBox Name="StudentsListBox" ItemsSource="{Binding Students}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0" Background="Transparent" IsHitTestVisible="False" PreviewGotKeyboardFocus="StudentsListBox_PreviewGotKeyboardFocus">

    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Padding" Value="0"/>
            <Setter Property="Margin" Value="0"/>

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Border x:Name="Bd">
                            <ContentPresenter/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelectionActive" Value="False" />
                                    <Condition Property="IsSelected" Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter TargetName="Bd" Property="Background" Value="Yellow" />
                                <Setter TargetName="Bd" Property="BorderBrush" Value="Transparent" />
                            </MultiTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid Margin="0,0,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Name="GradeBlock" Text="{Binding Grade}" FontSize="12" Margin="0,0,5,0"/>
                <TextBlock Grid.Column="1" Name="NameTextBlock" Text="{Binding Name}" FontSize="12" TextWrapping="Wrap"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ListBox>

private void StudentsListBox_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    e.Handled = true;
}

-1

对我来说最好的解决方案是:

        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Focusable" Value="True"/>
                <Setter Property="IsHitTestVisible" Value="False" />
            </Style>
        </ListBox.ItemContainerStyle>


-3

要禁用列表框/下拉列表中的一个或多个选项,您可以添加“ disabled”属性,如下所示。这样可以防止用户选择此选项,并且它会显示为灰色。

ListItem item = new ListItem(yourvalue, yourkey);
item.Attributes.Add("disabled","disabled");
lb1.Items.Add(item);

那个时候,您挺高的,并用ASP.NET解决方案回答了WPF问题。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.