在 WPF 中将 Int 属性数据绑定到 Enum

Posted

技术标签:

【中文标题】在 WPF 中将 Int 属性数据绑定到 Enum【英文标题】:Data binding Int property to Enum in WPF 【发布时间】:2014-01-09 12:35:24 【问题描述】:

下面是我拥有的一个类的简化示例:

public class ExampleClassDto 

     public int DriverTypeId

我还有一个 Enum,它将 DriverType 的 Id 映射到有意义的名称:

public enum DriverType

    None,
    Driver1,
    Driver2,
    Driver3

但我想在 XAML 中将它绑定到组合框。不幸的是,由于类型不匹配,它不喜欢这样。所以在我的 ViewModel 中,我必须创建第二个属性来映射两者

public class ExampleViewModel

    private ExampleClassDto _selectedExampleClass;
    public ExampleClassDto SelectedExampleClass
    
        get  return _selectedExampleClass; 
        set
        
            _selectedExampleClass = value;
            SelectedDriverType = (DriverType)_selectedExampleClass.DriverTypeId;
            OnPropertyChanged("SelectedDeviceType");
        
    

public DriverType SelectedDriverType

    get
        
            if (_selectedDeviceType != null) 
             
                return (DriverType)_selectedDeviceType.DriverTypeId;
            
            return DriverType.None;
        
        set
        
            _selectedDeviceType.DriverTypeId = (int) value;
            OnPropertyChanged("SelectedDriverType");
        


然后我绑定到新属性。

<ComboBox ItemsSource="Binding Source=StaticResource DriverTypeEnum" SelectedValue="Binding SelectedDriverType, Mode=TwoWay"/>

现在,这可行,但感觉很恶心。它使用 SelectedDriverType 作为转换器。我想避免使 DTO 的属性成为不同的类型。还有其他更优雅的解决方案吗?

谢谢!

【问题讨论】:

DriverTypeId 不能是 DriverType 类型吗? 可以,但是 Dto 来自一个单独的库,我现在无法更改 =\ 那么为什么不扩展现有的类 (public partial class) 并创建一个类型为 DriverType 的属性来获取/设置 DriverTypeId 呢? @gleng:我认为,在这种情况下,我宁愿只保留转换器属性。我想知道是否还有其他方法可以在 XAML 中使用 SelectedValue 或 SelectedItem,或者 ValueConverter 是否可以发挥作用 我记得我做了一个通用的IntToEnum 转换器,我会大量使用它。 ConverterParameter 通常设置为 x:Type local:MyEnum 以将枚举类型传递给它,它会将绑定的 int 转换为该枚举值/从该枚举值转换。可能值得花点时间为您的公共图书馆制作一个。 【参考方案1】:

接受的答案要求您将枚举的类型指定为每个绑定的转换器参数。

如果您绑定到枚举属性,转换器可以从targetType 属性中确定枚举类型,这样更符合人体工程学且不易出错。

public sealed class BidirectionalEnumAndNumberConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        if (value == null)
            return null;

        if (targetType.IsEnum)
        
            // convert int to enum
            return Enum.ToObject(targetType, value);
        

        if (value.GetType().IsEnum)
        
            // convert enum to int
            return System.Convert.ChangeType(
                value,
                Enum.GetUnderlyingType(value.GetType()));
        

        return null;
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        // perform the same conversion in both directions
        return Convert(value, targetType, parameter, culture);
    

无论底层枚举类型如何(intshortbyte...),这也适用。

调用时,此转换器会根据 valuetargetType 值在 int/enum 值之间翻转值的类型。源代码中没有硬编码的枚举类型,因此可重用。

【讨论】:

这似乎不适用于组合框,因为所选值是对象。接收 int 时的目标类型将是 object,因此您将不知道要转换为哪个枚举。 @aliceraunsbaek 你是对的,绑定目标必须提供枚举类型才能使这种方法工作。在像您这样的情况下,接受的答案可能会更好。 我已经通过添加一个可选的EnumType 属性来解决这个问题,该属性在设置后将取代targetType。基本上,转换器可以在两种不同的模式下运行:静态,枚举类型被显式设置;或动态,由Convert 参数确定。【参考方案2】:

你可以有一个通用转换器说EnumConverter,它将convert int to Enum在XAML上显示它,convert back from Enum to int在你的ViewModel类中设置。

它适用于任何枚举类型。您只需要在转换器参数中传递枚举类型即可。

public class EnumConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, 
                          System.Globalization.CultureInfo culture)
    
        Enum enumValue = default(Enum);
        if (parameter is Type)
        
            enumValue = (Enum)Enum.Parse((Type)parameter, value.ToString());
        
        return enumValue;
     

     public object ConvertBack(object value, Type targetType, object parameter, 
                               System.Globalization.CultureInfo culture)
     
         int returnValue = 0;
         if (parameter is Type)
         
             returnValue = (int)Enum.Parse((Type)parameter, value.ToString());
         
         return returnValue;
     

XAML 用法:

<ComboBox ItemsSource="Binding Source=StaticResource DriverTypeEnum"
          SelectedValue="Binding DriverTypeId,
                                Converter=StaticResource EnumConverter, 
                                ConverterParameter=x:Type local:DriverType"/>

local 是声明 DriverType 的命名空间。

【讨论】:

太棒了。那效果很好。只需将以下内容添加到我的主资源字典中,我就可以使用 EnumConverter 作为资源:&lt;converter:EnumConverter xmlns:converter="clr-namespace:Some.Name.Space.Helpers" x:Key="EnumConverter"/&gt;。非常高兴我可以在其他使用枚举的 ViewModel 中重用它。谢谢!【参考方案3】:

首先将枚举存储为 int 是一个坏主意。无论如何,我会使用双向代理属性而不是单独的类:

public int DriverTypeId  get; set; 

public DriverType IntAsEnum // proxy property, doesn't store any value, only does the conversion

    get  return (DriverType)DriverTypeId; 
    set  DriverTypeId = (int)value; 

【讨论】:

您能否提供更多信息,为什么这是一个坏主意? 见:原始痴迷

以上是关于在 WPF 中将 Int 属性数据绑定到 Enum的主要内容,如果未能解决你的问题,请参考以下文章

如何在C#中将列表与WPF数据网格绑定?

WPF绑定Radiobutton到enum

WPF 绑定无法与 int 类型的属性一起正常工作

如何将 Dictionary<enum, bool> 双向绑定到 WPF 中的 ListView 列?

Enum Binding ItemsSource In WPF

Enum Binding ItemsSource In WPF