【问题标题】:WPF ComboBox disabled item still selectable on borderWPF ComboBox 禁用的项目仍然可以在边框上选择
【发布时间】:2020-09-07 05:38:56
【问题描述】:

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

我尝试将文本框的边距和组合框项的填充设置为 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>

没有禁用任何项目

【问题讨论】:

  • 是否需要IsEnabled,如果在不可交互的情况下使用IsVisible Flag让它不可见呢?
  • 不幸的是,“IsVisible”是只读属性。我将尝试使用样式隐藏项目以将“可见性”更改为“折叠”。但我仍然想知道如何完全禁用组合框项,以及我在代码中犯错的地方。
  • 能否添加名为 ComboboxItemsDisabledConverter 的静态资源代码
  • 因为 wpf 代码对我来说似乎很好。
  • 开始消息已更新

标签: c# wpf combobox


【解决方案1】:

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

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

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

要解决您的问题,您必须禁用容器。为此,您必须在ItemContainerStyle 中定义触发器或设置器。注意这个StyleDataContext是数据模型(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>

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

ViewModel.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;
  }
}

MainWindow.xaml

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

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

【讨论】:

  • 我建议按照上一个例子的过滤方式。
  • 过滤器仅适用于ICollectionView。这意味着只有控件的 ItemsSource 被过滤,而原始的 NICs 集合仍然包含所有项目。
猜你喜欢
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 2015-12-24
  • 2019-05-06
  • 2015-08-02
相关资源
最近更新 更多