繁体   English   中英

用枚举值绑定combobox并以枚举的形式获取选中项

[英]Binding combobox with an Enumeration value and get the selected item in the form of enum

我有一个枚举:

public enum InspectionCardsGroupOption
   {
      Application = 0,
      ApplicationType,
      InspectionStation,
      ComponentSide
   };

现在我正在使用 wpf MVVM 设计模式。 此枚举在 ViewModel 中。 我在 xaml 中有一个 ComboBox。 我需要将该 ComboBox 绑定到这个枚举,并且在 ComboBox 的选择更改时,它应该以枚举值的形式给我枚举值。

平台:windows10,语言:C# 我是编程新手,所以如果有人能给我详细的解释,那对我会有帮助。

首先在 xaml 中创建一个 ObjectDataProvider,如下所示在 Resource 标签内:

<ObjectDataProvider  x:Key="odpEnum"
                         MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="local:Comparators"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    <local:EnumDescriptionConverter x:Key="enumDescriptionConverter"></local:EnumDescriptionConverter>

现在在上面的代码示例中,sys:Enum 有一个别名 sys,它来自命名空间 xmlns:sys="clr-namespace:System;assembly=mscorlib"。 所以需要添加这个。

添加一个组合框,如下所示:

<ComboBox Grid.Row="1" Grid.Column="1"  Height="25" Width="100" Margin="5" 
          ItemsSource="{Binding Source={StaticResource odpEnum}}"
          SelectedItem="{Binding Path=MySelectedItem}"
          >
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Converter={StaticResource enumDescriptionConverter}}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

让我考虑您有一个枚举类型,如下所示:

public enum Comparators
{
    [Description("Application")]
    Application,
    [Description("Application Type")]
    ApplicationType,
    [Description("Inspection Name")]
    InspectionName,
    [Description("Component Type")]
    ComponentType
}

所以将它保存在 viewmodel 部分(在视​​图模型之外,但在与视图模型相同的命名空间内)

现在在 viewmodel 中创建一个属性,如下所示从 XAML ComboBox 中获取 selectedItem

private Comparators _MySelectedItem;
    public Comparators MySelectedItem
    {
        get { return _MySelectedItem; }
        set
        {
            _MySelectedItem = value;
            OnPropertyChanged("MySelectedItem");
        }
    }

创建一个转换器类,如下所示:--

public class EnumDescriptionConverter : IValueConverter
{
    private string GetEnumDescription(Enum enumObj)
    {
        FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());

        object[] attribArray = fieldInfo.GetCustomAttributes(false);

        if (attribArray.Length == 0)
        {
            return enumObj.ToString();
        }
        else
        {
            DescriptionAttribute attrib = attribArray[0] as DescriptionAttribute;
            return attrib.Description;
        }
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {            
        Enum myEnum = (Comparators)value;            
        string description = GetEnumDescription(myEnum);
        return description;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return string.Empty;
    }
}

当您运行此示例时,您会发现您将在 _MySelectedItem = value 中获得 selectedItem 作为枚举类型; 在视图模型的属性中。

这可以通过 MVVM 纯粹的方式通过几个辅助类来实现。

myValueDisplayPair.cs

/// <summary>
/// Equivalent to KeyValuePair<object, string> but with more memorable property names for use with ComboBox controls
/// </summary>
/// <remarks>
/// Bind ItemsSource to IEnumerable<ValueDisplayPair>, set DisplayMemberPath = Display, SelectedValuePath = Value, bind to SelectedValue
/// </remarks>
public abstract class myValueDisplayPair
{
    public object Value { get; protected set; }
    public string Display { get; protected set; }
}

/// <summary>
/// Equivalent to KeyValuePair<T, string>
/// </summary>
/// <typeparam name="T"></typeparam>
public class myValueDisplayPair<T> : myValueDisplayPair
{
    internal perValueDisplayPair(T value, string display)
    {
        Value = value;
        Display = display;
    }

    public new T Value { get; }

    public override string ToString() => $"Display: {Display} Value: {Value}";
}

myEnumHelper.cs

/// <summary>
/// Helper class for enum types 
/// </summary>
public static class myEnumExtender
{
    /// <summary>
    /// Get the value of a Description attribute assigned to an enum element 
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string Description(this Enum value)
    {
        var fieldInfo = value
            .GetType()
            .GetField(value.ToString());

        var attributes = fieldInfo
            .GetCustomAttributes(typeof(DescriptionAttribute), false)
            .OfType<DescriptionAttribute>()
            .ToList();

        return attributes.Any() ? attributes.First().Description : value.ToString();
    }

    /// <summary>
    /// Gets all the elements of an enum type 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <remarks>
    /// c# doesn't support where T: Enum - this is the best compromise
    /// </remarks>
    public static ReadOnlyCollection<T> GetValues<T>() 
        where T : struct, IComparable, IFormattable, IConvertible
    {
        var itemType = typeof (T);

        if (!itemType.IsEnum)
            throw new ArgumentException($"Type '{itemType.Name}' is not an enum");

        var fields = itemType
            .GetFields()
            .Where(field => field.IsLiteral);

        return fields
            .Select(field => field.GetValue(itemType))
            .Cast<T>()
            .ToList()
            .AsReadOnly();
    }

    /// <summary>
    /// Generate a <see cref="myValueDisplayPair"/> list containing all elements of an enum type
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sortByDisplay"></param>
    public static ReadOnlyCollection<myValueDisplayPair<T>> MakeValueDisplayPairs<T>(bool sortByDisplay = false) 
        where T : struct, IComparable, IFormattable, IConvertible
    {
        var itemType = typeof(T);

        if (!itemType.IsEnum)
            throw new ArgumentException($"Type '{itemType.Name}' is not an enum");

        var values = GetValues<T>();
        var result = values
            .Select(v => v.CreateValueDisplayPair())
            .ToList();

        if (sortByDisplay)
            result.Sort((p1, p2) => string.Compare(p1.Display, p2.Display, StringComparison.InvariantCultureIgnoreCase));

        return result.AsReadOnly();
    }
}

这些可以在您的 ViewModel 中使用

public ReadOnlyCollection<lcValueDisplayPair<InspectionCardsGroupOption>> AllInspectionCardsGroupOptions { get; } 
    = myEnumExtender.MakeValueDisplayPairs<InspectionCardsGroupOption>();

private InspectionCardsGroupOption _selectedInspectionCardsGroupOption;

public InspectionCardsGroupOption SelectedInspectionCardsGroupOption
{
    get => _selectedInspectionCardsGroupOption;
    set => Set(nameof(SelectedInspectionCardsGroupOption), ref _selectedInspectionCardsGroupOption, value)
}

并在您的视图中

<ComboBox ItemsSource="{Binding AllInspectionCardsGroupOptions}"
          DisplayMemberPath="Display"
          SelectedValuePath="Value"
          SelectedValue="{Binding SelectedAllInspectionCardsGroupOptions, mode=TwoWay}" 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM