将 UWP ComboBox ItemsSource 绑定到 Enum

Posted

技术标签:

【中文标题】将 UWP ComboBox ItemsSource 绑定到 Enum【英文标题】:Bind UWP ComboBox ItemsSource to Enum 【发布时间】:2017-01-05 16:43:32 【问题描述】:

可以在 WPF 应用程序中使用 ObjectDataProvider 将枚举的字符串值绑定到 ComboBox 的 ItemsSource,如 this question 所示。

但是,当在 UWP 应用程序中使用类似的 sn-p 时,ff.显示错误信息:

“Windows 通用项目不支持 ObjectDataProvider。”

在 UWP 中有一个简单的替代方法吗?

【问题讨论】:

【参考方案1】:

下面是我的一个原型中的一个工作示例。

枚举

public enum GetDetails

    test1,
    test2,
    test3,
    test4,
    test5

ItemsSource

var _enumval = Enum.GetValues(typeof(GetDetails)).Cast<GetDetails>();
cmbData.ItemsSource = _enumval.ToList();

这会将组合框绑定到枚举值。

【讨论】:

感谢您的意见。你知道我是否可以使用与此等效的 XAML 吗? 很简单。创建一个返回字符串的视图模型。并在您的 UI 上设置数据上下文和 XAML 中的绑定。【参考方案2】:

如果您尝试通过 xaml 和 Bindings 设置 SelectedItem,请确保首先设置 ItemsSource!

例子:

<ComboBox ItemsSource="Binding ..." SelectedItem="Binding ..."/>

【讨论】:

【参考方案3】:

相信我,UWP 中的 ComboBox 和枚举是个坏主意。节省一些时间,不要在 UWP 的组合框上使用枚举。花了几个小时试图让它工作。您可以尝试其他答案中提到的解决方案,但您会遇到的问题是,当 SelectedValue 绑定到枚举时,propertychange 不会触发。所以我只是将它转换为int。

您可以在 VM 中创建一个属性并将枚举 GetDetails 转换为 int。

public int Details

  get  return (int)Model.Details; 
  set  Model.Details = (GetDetails)value; OnPropertyChanged();

然后你可以用int和string处理一个类的列表,不确定你是否可以使用KeyValuePair

public class DetailItem

  public int Value get;set;
  public string Text get;set;


public IEnumerable<DetailItem> Items

  get  return GetItems(); 


public IEnumerable<DetailItem> GetItems()

   yield return new DetailItem()  Text = "Test #1", Value = (int)GetDetails.test1 ; 
   yield return new DetailItem()  Text = "Test #2", Value = (int)GetDetails.test2 ; 
   yield return new DetailItem()  Text = "Test #3", Value = (int)GetDetails.test3 ; 
   // ..something like that

然后在 Xaml 上

<Combobox ItemsSource="Binding Items, UpdateSourceTrigger=PropertyChanged"
 SelectedValue="Binding Details, UpdateSourceTriggerPropertyChanged, Mode=TwoWay"
 SelectedValuePath="Value" 
 DisplayMemberPath="Text" />

【讨论】:

【参考方案4】:

我知道这是一篇旧帖子,但是 将您的组合框的 SelectedIndex 绑定到枚举属性并像这样定义您的值转换器,

    public object Convert(object value, Type targetType, object parameter, string language)
    
        string v = value.ToString();
        string[] vs = Enum.GetNames(typeof(YourEnumType));
        int index = vs.IndexOf(v);
        if (index > -1)
            return index;
        return 0;
    


    public object ConvertBack(object value, Type targetType, object parameter, string language)
    
        int index = (int)value;
        if (index > -1)
            return (YourEnumType)index;
        return YourEnumType.DefaultValue;
    

【讨论】:

【参考方案5】:

这是我为 UWP 提供的最简单、最通用的枚举绑定方式。也许这可以帮助某人,因为这很容易绑定和本地化。

/// <summary>
///     Helper class to bind an Enum type as an control's ItemsSource.
/// </summary>
/// <typeparam name="T"></typeparam>
public class EnumItemsSource<T> where T : struct, IConvertible

    public string FullTypeString  get; set; 
    public string Name  get; set; 
    public string LocalizedName  get; set; 
    public T Value  get; set; 

    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="fullString"></param>
    public EnumItemsSource(string name, T value, string fullTypeString)
    
        if (!typeof(T).IsEnum)
            throw new ArgumentException("EnumItemsSource only accept Enum type.");

        Name = name;
        Value = value;
        FullTypeString = fullTypeString;

        // Retrieve localized name
        LocalizedName = AppResource.GetResource(FullTypeString.Replace('.', '-'));
    

    /// <summary>
    ///     Create a list of EnumItemsSource from an enum type.
    /// </summary>
    /// <returns></returns>
    public static List<EnumItemsSource<T>> ToList()
    
        // Put to lists
        var namesList = Enum.GetNames(typeof(T));
        var valuesList = Enum.GetValues(typeof(T)).Cast<T>().ToList();

        // Create EnumItemsSource list
        var enumItemsSourceList = new List<EnumItemsSource<T>>();
        for (int i = 0; i < namesList.Length; i++)
            enumItemsSourceList.Add(new EnumItemsSource<T>(namesList[i], valuesList[i], $"typeof(T).Name.namesList[i]"));

        return enumItemsSourceList;
    

在 ViewModel 中:

    public List<EnumItemsSource<AccountType>> AccountTypes
    
        get => EnumItemsSource<AccountType>.ToList();
    

在视图中:

<ComboBox ItemsSource="Binding AccountTypes" DisplayMemberPath="LocalizedName" SelectedValuePath="Value" SelectedValue="Binding Path=Account.Type, Mode=TwoWay" />

【讨论】:

【参考方案6】:

ComboBoxItemSource 到 Enum,也与 SelectedItem。并且可以选择用自定义字符串替换 Enum 的名称(例如翻译)。尊重 MVVM 模式。

枚举:

public enum ChannelMark

   Undefinned,Left, Right,Front, Back

视图模型

private ChannelMark _ChannelMark = ChannelMark.Undefinned;

public ChannelMark ChannelMark

    get => _ChannelMark;
    set => Set(ref _ChannelMark, value);


private List<int> _ChannelMarksInts = Enum.GetValues(typeof(ChannelMark)).Cast<ChannelMark>().Cast<int>().ToList();

public List<int> ChannelMarksInts

    get => _ChannelMarksInts;
    set => Set(ref _ChannelMarksInts, value);

XAML

<ComboBox ItemsSource="x:Bind ViewModel.ChannelMarksInts"  SelectedItem="x:Bind ViewModel.ChannelMark, Converter=StaticResource ChannelMarkToIntConverter, Mode=TwoWay">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="Binding  Converter=StaticResource IntToChannelMarkConverter"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

转换器:

switch ((ChannelMark)value)

    case ChannelMark.Undefinned:
        return "Undefinned mark";
    case ChannelMark.Left:
        //translation
        return Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView().GetString("ChannelMarkEnumLeft");
    case ChannelMark.Right:
        return "Right Channel";
    case ChannelMark.Front:
        return "Front Channel";
    case ChannelMark.Back:
        return "Back Channel";
    default:
        throw new NotImplementedException();




public class IntToChannelMarkConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, string language) => ((ChannelMark)value).ToString();
    public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException();


【讨论】:

【参考方案7】:

我使用了 Karnaltas 答案,因为它支持使用 resx 文件轻松本地化。但是我在往返于我的实体的双向绑定方面遇到了麻烦。我通过将绑定更改为使用 SelectedIndex 并添加一个转换器解决了这个问题。这样,组合框正确地拾取初始状态以及显示它。

ViewModel 与 Karnalta 的解决方案保持一致。

在视图中更改绑定:

<ComboBox ItemsSource="Binding AccountTypes" DisplayMemberPath="LocalizedName" SelectedIndex=x:Bind ViewModel.Account.Type, Mode=TwoWay, Converter=StaticResource EnumToIntConverer" />

新转换器:

public class EnumToIntConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, string language)
               
        return (int)value;
    

    public object ConvertBack(object value, Type targetType, object parameter, string language)
                
        return Enum.Parse(targetType, value.ToString());
    

别忘了在页面/控件中添加转换器:

<Grid.Resources>
    <ResourceDictionary>
        <converters:EnumToIntConverter x:Key="EnumToIntConverter" />
    </ResourceDictionary>
</Grid.Resources>

【讨论】:

以上是关于将 UWP ComboBox ItemsSource 绑定到 Enum的主要内容,如果未能解决你的问题,请参考以下文章

UWP Combobox 项目无缘无故滚动到中间

[UWP]新控件ColorPicker

[UWP]新控件ColorPicker

UWP使用 Rx 改善 AutoSuggestBox

UWP使用 Rx 改善 AutoSuggestBox

在 ViewBox 内缩放 ComboBox 弹出窗口