首页 > 解决方案 > WPF ComboBox 禁用的项目仍然可以在边框上选择

问题描述

当我禁用某些组合框项目时,它们在嵌套文本块的左右边界上保持可选状态。

组合框截图

我尝试将文本框的边距和组合框项的填充设置为 0,然后我尝试将文本框和组合框项的 Horizo​​ntalAlignment 属性设置为“Stretch”,但没有结果。

WPF:

<Window.Resources>
    <local:ComboboxItemsDisableConverter x:Key="ComboboxItemsDisableConverter"/>
</Window.Resources>

<ComboBox x:Name="comboBox" HorizontalAlignment="Right" Margin="0,13,10,0" Width="441"
SelectedIndex="{Binding ViewModel.SelectedNic, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" 
ItemsSource="{Binding ViewModel.NICs, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" 
SelectionChanged="ComboBox_SelectionChanged" 
IsReadOnly="True" Height="25" VerticalAlignment="Top" Grid.Row="2">
    <ComboBox.ItemContainerStyle>
        <Style TargetType="ComboBoxItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        </Style>
    </ComboBox.ItemContainerStyle>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <ComboBoxItem IsEnabled="{Binding OperationalStatus, Converter={StaticResource ComboboxItemsDisableConverter}}" >
                <TextBlock HorizontalAlignment="Stretch" Text="{Binding Description}" />
            </ComboBoxItem>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

ComboBoxItemsDisableConverter 类:

class ComboboxItemsDisableConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
        if (value == null) return value;
        var Status = (OperationalStatus)value;

        if (Status != OperationalStatus.Up)
            return true;
        else
            return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        throw new NotImplementedException();
    }
}

我能做些什么来完全防止选择禁用的项目?

隐藏项目适用于以下代码:

<ComboBox.ItemContainerStyle>
            <Style TargetType="ComboBoxItem">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=OperationalStatus, Converter={StaticResource ComboboxItemsDisableConverter}}" Value="true">
                        <Setter Property="Visibility" Value="Collapsed"></Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ComboBox.ItemContainerStyle>

如果我使用这个标记

<ComboBox x:Name="comboBox" HorizontalAlignment="Right" Margin="0,13,10,0" Width="441" SelectedIndex="{Binding SelectedNic}"  ItemsSource="{Binding NICs}" SelectionChanged="ComboBox_SelectionChanged" IsReadOnly="True" Height="25" VerticalAlignment="Top" Grid.Row="1">
        
        <ComboBox.ItemTemplate>
            <DataTemplate>                    
                    <TextBlock HorizontalAlignment="Stretch" Text="{Binding Description}" IsEnabled="{Binding OperationalStatus, Converter={StaticResource ComboboxItemsDisableConverter}}"></TextBlock>                    
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

没有禁用任何项目

标签: c#wpfcombobox

解决方案


您试图禁用项目容器内容,而不是项目容器。

您必须了解ItemsControl它的ItemsSource. 通常这些项目是数据模型。这些模型然后被包装到一个容器中。数据模型通常不是 type FrameworkElement,它们是普通数据类型。为了呈现元素,它们必须是 type FrameworkElement,这就是模型被包装到容器中的原因,例如ComboBoxItem. 您可以通过定义一个ItemTemplate.

您不与数据模型(容器内容)交互,而是与项目容器交互。当您只禁用内容时,您仍然可以与容器交互。该项目本身已Padding应用。因此仍有足够的区域允许交互。

要解决您的问题,您必须禁用容器。为此,您必须在ItemContainerStyle. 请注意,DataContextStyle是数据模型( 中的项目ItemsSource):

<ComboBox>
  <ComboBox.ItemContainerStyle>
    <Style TargetType="ComboBoxItem">
      <Setter Property="IsEnabled" 
              Value="{Binding OperationalStatus, Converter={StaticResource ComboboxItemsDisableConverter}}" />
    </Style>
  </ComboBox.ItemContainerStyle>

  <!-- Remove the IsEnabled binding! -->
  <ComboBox.ItemTemplate>
    <DataTemplate>                    
      <TextBlock HorizontalAlignment="Stretch" 
                 Text="{Binding Description}" />
    </DataTemplate>
  </ComboBox.ItemTemplate>
</ComboBox>

请注意,从用户的角度来看,建议使用过滤从源集合中删除禁用的项目。不要显示占用空间且不允许交互的内容。这可能会让人很困惑,特别是如果用户不理解项目被禁用的原因以及他如何启用它们以选择它们时。

视图模型.cs

class ViewModel
{
  public ObservableCollection<MyModel> NICs { get; }

  public ViewModel()
  {
    this.NICs = new ObservableCollection<MyModel>();

    // Only show items where OperationalStatus == OperationalStatus.Up
    CollectionViewSource.GetDefaultView(this.NICs).Filter = 
      item => (item as MyModel).OperationalStatus == OperationalStatus.Up;
  }
}

主窗口.xaml

<Window>
  <Window.DataContext>
    <ViewModel  />
  </Window.DataContext>

  <ComboBox ItemsSource="{Binding NICs}" />
</Window>

推荐阅读