我有一个带枚举属性的模型(在这种情况下,与出口管制法规相关)。当向用户显示值时,我想显示相应的字符串。有时这是在ComboBox中(用户可以选择一个值),有时它在TextBlock中(它是只读的)。
示例:对于ExportRegulationType.EAR
,我想显示"EAR"
,而对于ExportRegulationType.DoNotExport
,我想显示"Do Not Export"
。请注意,我没有任何语言本地化需求,但我认识到这个问题......
目前,在我的ViewModel中,我有一个属性,它返回基于当前枚举值的字符串,以及另一个返回Dictionary<ExportRegulationType, string>
的属性。对于ComboBoxes,我可以将ItemsSource
绑定到dictionary属性,对于TextBlocks,我可以绑定到string属性。这有效,但有点笨拙。
两个问题:
1)在我看来,我应该能够将字典(带有键和值)声明为XAML中的静态资源(可能在App.xaml中),并将其用于ComboBox版本的ItemsSource。但是,我无法弄清楚如何声明和引用这样的东西。我怎么能这样做?
2)假设上面已经到位,我认为我也可以设置与textblock的绑定,所以基于enum属性,它将在字典中查找字符串。
我看到以下与static或dynamic枚举值有关的问题。第一个是不够的,第二个没有回答......
这些应该只是一个XAML,并且可以让我从ViewModel中删除方法(只有一个公开的ExportRegulationType
枚举属性。这些可能吗?
编辑:其他信息:
在应用程序中,我将有许多不同的视图,模型和ViewModel。但是,由于出口管制法规是一个共同且一致的要求,我使用组合来保持干燥。即,模型A和B都具有ExportControl模型。 ViewModels A1,A2,B1和B2将具有ExportControlViewModel。视图将具有绑定到其ViewModel的ExportControlViewModel的控件。视图将具有ComboBox或TextBlock,但不能同时具有两者(取决于用户是否可以更改值)。
答案 0 :(得分:3)
我不知道这是否适用于您的情况,但这是一个可能的解决方案。在视图模型中,公开ExportRegulationType属性,然后创建value converter以显示所需的字符串。
首先创建你的价值转换器:
class ExportRegulationTypeToStringConverter: IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ExportRegulationType regType = (ExportRegulationType)value;
switch(regType)
{
case ExportRegulationType.EAR:
return "EAR";
case ExportRegulationType.DoNotExport:
return "Do Not Export";
//handle other cases
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
#endregion
}
然后在xaml中添加对转换器的引用。 local 是您的类所在的命名空间。
<local:ExportRegulationTypeToStringConverter x:Key="exportRegConverter" />
最后,设置文本框的值以使用转换器。 pathToEnum 是在ExportRegulationType类型的ViewModel上公开的属性。
<TextBlock Text="{Binding pathToEnum, Converter={StaticResource exportRegConverter}}" />
使用ObjectDataProvider使用枚举值填充ComboBox。
<Window.Resources>
<ObjectDataProvider x:Key="dataFromEnum"
MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:ExportRegulationType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
现在我们创建ComboBox并使用带有value converter的容器样式来显示枚举所需的字符串。
<ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Content" Value="{Binding Converter={StaticResource exportRegConverter}}" />
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
答案 1 :(得分:2)
而不是Dictionary
你有另一种选择。
请参阅以下问题:WPF Binding a ListBox to an enum, displaying the Description Attribute
您可以在此枚举中添加Description
属性
public enum ExportRegulationType
{
[Description("EAR")]
EAR,
[Description("Do Not Export")]
DoNotExport
}
当您想要显示它时,您可以使用我链接的问题中找到的EnumDescriptionConverter
转换器
答案 2 :(得分:1)
使用ObjectDataProvider 然后将ComboBox的Items绑定到它,并将“DisplayMemberPath”设置为“Value”。
这应该是显示字典的值,但在代码隐藏中,SelectedValue
是KeyValuePair<>
。
对于您的文本块,请使用Binding
ElementName=yourcombobox
和Path=SelectedItem
:
<TextBlock Text="{Binding SelectedItem, ElementName=yourcombobox}" />
让我知道它是怎么回事=)
答案 3 :(得分:1)
我用@Dylan和@Meleak编写的内容混合解决了这个问题。我将这作为答案来展示最终的解决方案:
首先,我实现了一个IValueConverter,(根据@ Meleak的回答):
class EnumDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Enum regulation = (Enum)value;
return GetEnumDescription(regulation);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return String.Empty;
}
/// <summary>
/// Returns text intended for display based on the Description Attribute of the enumeration value.
/// If no Description Attribute is applied, the value is converted to a string and returned.
/// </summary>
/// <param name="enumObj">The enumeration value to be converted.</param>
/// <returns>Text of the Description Attribute or the Enumeration itself converted to string.</returns>
private string GetEnumDescription(Enum enumObj)
{
// Get the DescriptionAttribute of the enum value.
FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
object[] attributeArray = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributeArray.Length == 0)
{
// If no Description Attribute was found, default to enum value conversion.
return enumObj.ToString();
}
else
{
// Get the text of the Description Attribute
DescriptionAttribute attrib = attributeArray[0] as DescriptionAttribute;
return attrib.Description;
}
}
}
我标记了我的枚举(请注意,多个值未标记为所需的文本与值本身相同):
public enum ExportRegulationType
{
[Description("Not Determined")]
NotDetermined, // Export authority not determined
EAR, // Controlled by EAR Regulations
ITAR, // Controlled by ITAR Regulations
[Description("Do Not Export")]
DoNotExport, // Export not allowed
Unrestricted // Export not controlled
}
在我的App.xaml中,我声明ObjectDataProvider获取枚举值列表和EnumDisplayConverter(这里因为它们将被几个不同的视图使用):
<Application.Resources>
[Other stuff...]
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="ExportRegulationValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="models:ExportRegulationType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<local:EnumDescriptionConverter x:Key="ExportDisplayConverter"/>
</Application.Resources>
对于TextBlock:
<TextBlock Text="{Binding Export.Regulation, Converter={StaticResource ExportDisplayConverter}}"/>
对于组合框:
<ComboBox ItemsSource="{Binding Source={StaticResource ExportRegulationValues}}"
SelectedValue="{Binding Document.Export.Regulation}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource ExportDisplayConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
完美地!
答案 4 :(得分:0)
Here is a blog post of mine with an approach using attached behaviors.
基于不同的枚举值不需要限于切换字符串的原则。相反,您可以声明要表示每个值的任何UI(字符串,图像,不同的控件和布局等),并使用附加的行为来控制其可见性。
然后,您的情况可以被定义为具有两个不同的文本块,每个文本块都绑定到类型ExportRegulationType
的相同属性。由于他们受同一财产的约束,他们的可见性是相互排斥的:
<Grid>
<TextBlock
Text="EAR"
local:EnumVisibility.Value="{Binding ExportRegulationType}"
local:EnumVisibility.TargetValue="EAR"
/>
<TextBlock
Text="Do Not Export"
local:EnumVisibility.Value="{Binding ExportRegulationType}"
local:EnumVisibility.TargetValue="DoNotExport"
FontWeight="Bold"
/>
</Grid>
我包含了FontWeight="Bold"
,表明您可以为每个枚举值做出不同的决定。这也支持XAML本地化,因为文本设置与任何其他文本块一样。
有关解决方案,代码示例以及包含框架和示例应用程序的zip文件的完整演练,请参阅the post。
编辑以回复其他信息:
绑定到ComboBox
属性的ExportRegulationType
看起来像这样:
<ComboBox local:EnumSelector.SelectedValue="{Binding ExportRegulationType, Mode=TwoWay}">
<ComboBoxItem Content="EAR" local:EnumSelector.ItemValue="EAR" />
<ComboBoxItem Content="Do Not Export" local:EnumSelector.ItemValue="DoNotExport" />
</ComboBox>
我们将每个项目与枚举值相关联,然后使用TwoWay
绑定到EnumSelector.SelectedValue
,这样只要它发生变化,它就会回写到视图模型的属性。
这提供了与文本块相同的灵活性:您可以做出关于如何设置文本以及每个项目包含的内容的任何决定。