将 UWP ComboBox ItemsSource 绑定到 Enum
Bind UWP ComboBox ItemsSource to Enum
可以在 WPF 应用程序中使用 ObjectDataProvider
将枚举的字符串值绑定到 ComboBox 的 ItemsSource,如 this question.
中所示
但是,在 UWP 应用程序中使用类似的片段时,ff.显示错误消息:
"ObjectDataProvider is not supported in a Windows Universal project."
在 UWP 中是否有一个简单的替代方法来执行此操作?
下面是我的原型之一的工作示例。
枚举
public enum GetDetails
{
test1,
test2,
test3,
test4,
test5
}
ItemsSource
var _enumval = Enum.GetValues(typeof(GetDetails)).Cast<GetDetails>();
cmbData.ItemsSource = _enumval.ToList();
这会将组合框绑定到枚举值。
如果您尝试通过 xaml 和绑定设置 SelectedItem,请确保先设置 ItemsSource!
示例:
<ComboBox ItemsSource="{Binding ...}" SelectedItem="{Binding ...}"/>
ComboBox
和 ItemSource
到 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();
}
相信我,UWP 中的组合框和枚举不是个好主意。节省一些时间,不要在 UWP 的组合框中使用枚举。花了几个小时试图让它发挥作用。您可以尝试其他答案中提到的解决方案,但您将遇到的问题是 属性change 在 SelectedValue 绑定到枚举时不会触发。所以我只是将它转换为 int。
您可以在 VM 中创建一个 属性 并将枚举 GetDetails 转换为 int。
public int Details
{
get { return (int)Model.Details; }
set { Model.Details = (GetDetails)value; OnPropertyChanged();}
}
然后你可以只在 class 的列表上使用 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" />
我知道这是旧的 post,但是
将您的组合框的 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;
}
这是我为 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}" />
我使用了 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());
}
}
并且不要忘记在 page/control:
中添加转换器
<Grid.Resources>
<ResourceDictionary>
<converters:EnumToIntConverter x:Key="EnumToIntConverter" />
</ResourceDictionary>
</Grid.Resources>
可以在 WPF 应用程序中使用 ObjectDataProvider
将枚举的字符串值绑定到 ComboBox 的 ItemsSource,如 this question.
但是,在 UWP 应用程序中使用类似的片段时,ff.显示错误消息:
"ObjectDataProvider is not supported in a Windows Universal project."
在 UWP 中是否有一个简单的替代方法来执行此操作?
下面是我的原型之一的工作示例。
枚举
public enum GetDetails
{
test1,
test2,
test3,
test4,
test5
}
ItemsSource
var _enumval = Enum.GetValues(typeof(GetDetails)).Cast<GetDetails>();
cmbData.ItemsSource = _enumval.ToList();
这会将组合框绑定到枚举值。
如果您尝试通过 xaml 和绑定设置 SelectedItem,请确保先设置 ItemsSource!
示例:
<ComboBox ItemsSource="{Binding ...}" SelectedItem="{Binding ...}"/>
ComboBox
和 ItemSource
到 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();
}
相信我,UWP 中的组合框和枚举不是个好主意。节省一些时间,不要在 UWP 的组合框中使用枚举。花了几个小时试图让它发挥作用。您可以尝试其他答案中提到的解决方案,但您将遇到的问题是 属性change 在 SelectedValue 绑定到枚举时不会触发。所以我只是将它转换为 int。
您可以在 VM 中创建一个 属性 并将枚举 GetDetails 转换为 int。
public int Details
{
get { return (int)Model.Details; }
set { Model.Details = (GetDetails)value; OnPropertyChanged();}
}
然后你可以只在 class 的列表上使用 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" />
我知道这是旧的 post,但是 将您的组合框的 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;
}
这是我为 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}" />
我使用了 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());
}
}
并且不要忘记在 page/control:
中添加转换器<Grid.Resources>
<ResourceDictionary>
<converters:EnumToIntConverter x:Key="EnumToIntConverter" />
</ResourceDictionary>
</Grid.Resources>