在WPF中禁止/阻止选择已禁用的组合框项目

30

我正在编写一个应用程序,我希望在 ComboBox 中禁用一些项目,并且还想防止/阻止选择已被禁用的项目。请注意,在主窗口中的 ComboBox 具有另一个ComboBox作为 ComboBox 项初始化(这是由 DataTemplateSelector 在运行时决定的)。

使用下面的代码,我能够禁用嵌套的 ComboBox,但它不能阻止用户选择已禁用的 ComboBox 项。任何有关禁止/阻止选择已禁用项目的帮助都将有所帮助。

以下是代码片段

主窗口中的 ComboBox:

<Grid>
    <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" 
              Width="120" Margin="87.2,44.8,0,0" 
              ItemsSource="{Binding Cars}" 
              ItemsPanel="{DynamicResource ItemsPanelTemplateHorizontal}"
              ItemTemplateSelector="{StaticResource QualityComboBoxTemplateSelector}"
              SelectedItem="{Binding SelectedItm}"/>
</Grid>

数据模板选择器:

public class QualityComboBoxTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var element = container as FrameworkElement;

        var dataTemplate = element.FindResource(((item is string) && item.Equals("Ferrari")) ?
                                                       "DataTemplateTopLevelCombobox2" : "DataTemplateTopLevelCombobox1") as DataTemplate;

        return dataTemplate;
    }
}

上述ComboBox的数据模板:

<DataTemplate x:Key="DataTemplateTopLevelCombobox1">
    <Border BorderBrush="Black" BorderThickness="1" >
        <TextBlock HorizontalAlignment="Left" 
                   TextWrapping="Wrap" Text="{Binding}"     
                   VerticalAlignment="Top"/>
    </Border>
</DataTemplate>

<DataTemplate x:Key="DataTemplateTopLevelCombobox2">
    <Border Width="100">
        <ComboBox Text="Custom" Height="21.96"
        ItemsSource="{Binding DataContext.Models, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
        IsEnabled="{Binding DataContext.EnableCombo, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
    </Border>
</DataTemplate>
2个回答

49

您可以通过将ComboBoxItemIsEnabled属性设置为false来实现此目的;

因此,ComboBox中的每个项目的ItemSource(在您的情况下是Cars)可以是一个具有某些属性(比如IsSelectable)的对象,指定它是否应启用或禁用,然后使用样式使项目无法选择。类似这样 -

<Style TargetType="ComboBoxItem"> 
   <Setter Property="IsEnabled" Value="{Binding IsSelectable}"/> 
</Style> 

更新:

<Grid>
    <ComboBox
        Width="120"
        Margin="87.2,44.8,0,0"
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        ItemTemplateSelector="{StaticResource QualityComboBoxTemplateSelector}"
        ItemsPanel="{DynamicResource ItemsPanelTemplateHorizontal}"
        ItemsSource="{Binding Cars}"
        SelectedItem="{Binding SelectedItm}">
        <ComboBox.ItemContainerStyle>
            <Style TargetType="ComboBoxItem">
                <Setter
                    Property="IsEnabled"
                    Value="{Binding IsSelectable}" />
            </Style>
        </ComboBox.ItemContainerStyle>
    </ComboBox>
</Grid>

实际上我没有使用ComboboxItemStyle,我正在使用DataTemplate。 - vmore
@vmore,我已更新我的答案,展示了如何应用ComboBoxItem样式。 - akjoshi
10
这不是一个可靠的防止选择的方法。即使将焦点放在控件上并键入搜索,仍然可以选择已禁用的项目。它会毫无问题地被选中。 - Jordy Boom
@JordyBoom 谢谢Jordy,我还没有尝试过这种情况,但听起来很奇怪。如果你有任何解决此问题的变通方法或链接,请让大家知道。 - akjoshi
1
我希望我能做到,但现在我正在通过允许选择但防止任何进一步的操作来解决它(即,该选择被认为对表单无效)。您必须钩入查找行为以过滤掉所有禁用的项目。不过,这似乎是控件的一个明显错误,所以我不确定为什么它仍然会以这种方式运行。 - Jordy Boom
显示剩余2条评论

8
为了解决@JordyBoom指出的问题。
只有在下拉列表至少打开一次后,ItemsContainerGenerator才会生成项目。
因此,如果您在窗口加载事件处理程序中打开并关闭下拉列表,则鼠标和键盘选择都应该正常工作。
    public MainWindow()
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(onLoaded);
    }

    private void onLoaded(object sender, RoutedEventArgs e)
    {
         cmbx.IsDropDownOpen = true;
         cmbx.IsDropDownOpen = false;
    }

来源:WPF:使组合框项目无效 - 即使使用键盘访问时也是如此


1
谢谢。向上和向下箭头键可用于在组合框下拉之前浏览项目,并且可以允许在没有此修复的情况下进行选择。禁用的项目对于某些人来说是分隔符。 - James_UK_DEV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接