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

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

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

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

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

【问题讨论】:

    标签: c# combobox enums uwp uwp-xaml


    【解决方案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>
              

              【讨论】:

                猜你喜欢
                • 2018-08-02
                • 1970-01-01
                • 2015-04-07
                • 1970-01-01
                • 2019-12-11
                • 2020-01-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多