WPF 将枚举列表(或类似列表)绑定到复选框列表

Posted

技术标签:

【中文标题】WPF 将枚举列表(或类似列表)绑定到复选框列表【英文标题】:WPF binding Enum list (or similar) to list of checkboxes 【发布时间】:2012-05-05 20:07:22 【问题描述】:

我想将复选框列表绑定到 WPF 中的枚举值集合。 枚举不是 [Flags]。

上下文: 它用于过滤数据网格,其中每个项目都有一个我的枚举实例。 它不一定需要绑定到 List,固定大小的集合也可以。

【问题讨论】:

【参考方案1】:

假设您想绑定到枚举的所有可能值,您可以使用ObjectDataProvider 来完成。 在您的资源中声明这一点(Window.ResourcesApp.Resources 等):

    <ObjectDataProvider x:Key="enumValues" MethodName="GetValues" ObjectType="x:Type sys:Enum">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="local:TestEnum"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

这基本上表示对Enum.GetValues(typeof(TestEnum)) 的调用并将其公开为数据源。 注意:您需要先声明命名空间syslocal,其中sysclr-namespace:System;assembly=mscorliblocal 是您的枚举的命名空间。

一旦你有了它,你就可以像其他任何东西一样将该 ObjectDataProvider 用作绑定源,例如:

<ListBox ItemsSource="Binding Source=StaticResource enumValues"/>

这样做的非声明方式只是在代码中分配它:

someListBox.ItemsSource = Enum.GetValues(typeof(TestEnum));

对于绑定选定的项目,很遗憾不能从 Xaml 设置 SelectedItems 属性,但您可以使用 SelectionChanged 事件:

<ListBox Name="lb" ItemsSource="Binding Source=StaticResource enumValues" SelectionMode="Multiple" SelectionChanged="lb_SelectionChanged"></ListBox>

然后在事件中设置您的 ViewModel(或您使用的任何东西)上的属性:

private void lb_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    viewModel.SelectedValues = lb.SelectedItems.OfType<TestEnum>().ToList();

【讨论】:

谢谢,这适用于显示列表框。第二部分呢,将选定的值绑定到 List 或类似的? 谢谢。不好,它在 xaml 中不起作用 :(,因为我将 datacontext 设置为在运行时查看。 不起作用。 ObjectType="x:Type sys:Enum" 上的 DataObjectProvider 出错:“命名空间“clr-namespace:System;assembly=System”中不存在名称“Enum”。 @Nick 命名空间sys 必须映射到"clr-namespace:System;assembly=mscorlib"(不是程序集System 我讨厌它们在多个程序集中具有完全相同的命名空间。【参考方案2】:

这个适合你吗?它将任何 Enum 转换为字典,以便您可以访问 Enum 的内部整数以及它们的名称(用于显示)。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample

    class Sample
    
        public static IDictionary<String, Int32> ConvertEnumToDictionary<K>()
        
            if (typeof(K).BaseType != typeof(Enum))
            
                throw new InvalidCastException();
            
            return Enum.GetValues(typeof(K)).Cast<Int32>().ToDictionary(currentItem => Enum.GetName(typeof(K), currentItem));
        
    

编辑

您可以使用 ICollection 类型的 IDictionary 属性 KeysValues 来执行您想要的绑定。

myListBox.ItemsSource = myEnumDictionary.Keys;

当然也可以直接在 XAML 中完成。

<ListBox ItemsSource="Binding myEnumDictionary.Keys"></ListBox>

【讨论】:

部分合适,但我仍然不知道如何绑定选定的值。【参考方案3】:

下面是如何在没有任何代码或在您的视图中定义 DataObjectProviders 的情况下做到这一点。

第 1 步:创建一个新类,该类可以存储您的 ListBoxItem 的值,以及它是否被选中的属性。

需要实现INotifyPropetyChanged,才能支持是否选中的双向绑定。我将使它成为通用的,因此只需要定义一次并且可以重用于任何类型。如果您已经有一个实现 INotifyPropertyChanged 的​​基类,则可以直接继承该基类并忽略该类的前几行。

public class SelectableItem<T> : INotifyPropertyChanged

  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
  
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  

  public SelectableItem(T val)
  
    Value = val;
    _isSelected = false;
  

  public T Value  get; private set; 

  private bool _isSelected;
  public bool IsSelected
  
    get => _isSelected;
    set
    
      if (_isSelected == value) return;
      _isSelected = value;
      OnPropertyChanged();
    
  

第 2 步:将 SelectableItem 属性的集合添加到您的 ViewModel/DataContext。由于您的项目列表是可用枚举值的静态列表,因此无需将其实现为 ObservableCollection 或任何类似的东西。 ItemsSource 只需要 1 次绑定。

public class ViewModel : ViewModelBase

  public ViewModel()
  
    AvailableItems = typeof(TestEnum).GetEnumValues().Cast<TestEnum>().Select((e) => new SelectableItem<TestEnum>(e)).ToList();
  

  public IEnumerable<SelectableItem<TestEnum>> AvailableItems  get; private set; 

第 3 步:使用 ItemContainerStyle 允许绑定到 ListBoxItems 的 IsSelected 属性:

<ListBox ItemsSource="Binding AvailableItems, Mode=OneTime" SelectionMode="Extended">
  <ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
      <Setter Property="Content" Value="Binding Value"/>
      <Setter Property="IsSelected" Value="Binding IsSelected"/>
    </Style>
  </ListBox.ItemContainerStyle>
</ListBox>

要获取选定的项目,只需遍历 AvailableItems 属性并找到 IsSelected = true 的项目。您甚至可以添加一个只读属性来为您执行此操作:

public IEnumerable<TestEnum> SelectedItems

  get => AvailableItems.Where((o) => o.IsSelected).Select((o) => o.Value).ToList();

【讨论】:

【参考方案4】:

@Dummy01 说的是正确的,但我认为大多数人都需要得到结果 作为

Dictionary<int,string>

没有

Dictionary<string,int>

所以解决方案应该是

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sample

    class Sample
    
        public static IDictionary<String, Int32> ConvertEnumToDictionary<K>()
        
            if (typeof(K).BaseType != typeof(Enum))
            
                throw new InvalidCastException();
            
            return Enum.GetValues(typeof(K)).Cast<Int32>().ToDictionary(i => i, i => Enum.GetName(typeof(K), i));
        
    

所以现在你会得到KeyValuePair&lt;Int32,string&gt;

如果您将枚举用作 FLAGS,这将非常有用

[Flags]
public enum LogSystemLogType

   All = 1 << 1,
   CreateDatabase = 1 << 2,
   CreateContract = 1 << 3,

【讨论】:

很奇怪,有人否决了这个答案,我只是想分享这个信息。 :)

以上是关于WPF 将枚举列表(或类似列表)绑定到复选框列表的主要内容,如果未能解决你的问题,请参考以下文章

双向绑定到 WPF 中多个列表框上的 ListBox SelectedItem

WPF-将列表绑定到列表视图

WPF 自定义用户控件绑定在列表视图中始终返回 false

将 ObservableCollection 绑定到 WPF 列表框

如何将控件绑定到 WPF 列表视图列

如何将 DataGrid 中的文本框绑定到 Wpf 中的列表?