2011-08-26 92 views
5

我有一个枚举属性的模型(在这种情况下,与出口管制条例有关)。向用户显示值时,我想显示相应的字符串。有时这是在ComboBox中(用户可以选择一个值),有时它在TextBlock中(它是只读的)。将textblock绑定到XAML中的键的字典值?

例如:对于ExportRegulationType.EAR,我想显示"EAR",而对于ExportRegulationType.DoNotExport,我想显示"Do Not Export"。请注意,我没有任何语言本地化的需求,但我认识到这个问题...

目前,在我的ViewModel,我有一个属性返回一个字符串基于当前的枚举值,还有另一个属性返回Dictionary<ExportRegulationType, string>。对于组合框,我可以将ItemsSource绑定到字典属性,对于TextBlocks,我可以绑定到字符串属性。这有效,但有点笨拙。

两个问题:

1)在我看来,我应该能够申报词典(与键和值),如XAML(可能在App.xaml中)的静态资源,并利用它来进行ComboBox版本的ItemsSource。但是,我无法弄清楚如何声明和引用这样的事情。我怎样才能做到这一点?

2)假设上面已经存在,我想我也可以设置与textblock的绑定,所以根据enum属性,它会查找字典中的字符串。

我看到以下有关staticdynamic枚举值的问题。首先是不够的,第二个是没有回答......

这应该是一个XAML只,并将使我删除从我的ViewModel(只具有一个暴露ExportRegulationType所列财产的方法。这些是可能的

编辑:附加信息:

在应用程序中,我将有很多套不同的意见,模型和的ViewModels然而,由于出口控制法规是共同一致的要求,我正在使用合成来保持它干燥,即模型A和B都有一个ExportControl模型,ViewModels A1,A2,B1和B2将ha有一个ExportControlViewModel。视图将具有绑定到其ViewModel的ExportControlViewModel的控件。视图将有一个ComboBox或一个TextBlock,但不能同时使用(取决于用户是否可以更改该值)。

+0

添加了C#作为标签,所以答案得到语法突出显示 –

回答

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:ExportRegulationTypeToStringConverter x:Key="exportRegConverter" /> 

最后,将文本框的值设置为使用转换器。 pathToEnum是暴露在您的ViewModel类型ExportRegulationType上的属性。

<TextBlock Text="{Binding pathToEnum, Converter={StaticResource exportRegConverter}}" /> 

使用ObjectDataProvider来使用enum的值填充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> 

现在我们创建一个组合框,并使用一个容器的风格与我们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> 
+0

我希望我可以选择两个答案;我正在给你正确的方向迅速的信贷,并需要更多的代表! – mbmcavoy

+0

哦,注意:使用ComboBox.ItemContainerStyle几乎可以工作 - 下拉列表中的项目是正确的。但是,选择某个项目并关闭下拉列表时,会显示enum.ToString()值。使用数据模板而不是正常工作。 – mbmcavoy

1

使用ObjectDataProvider 然后绑定组合框的项目给它,并设置“的DisplayMemberPath”到“值”。

这个应该做的是显示你的字典的值,但在代码后面的SelectedValueKeyValuePair<>

为了您的文字块,使用Binding使用ElementName=yourcomboboxPath=SelectedItem

<TextBlock Text="{Binding SelectedItem, ElementName=yourcombobox}" /> 

让我知道如何去=)

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转换器中的问题找到我链接

+0

油滑。如。哎呀!我喜欢将字符串定义嵌入到枚举中,并且转换器(稍作调整)对于任何枚举都是通用的,并且没有描述属性就是优雅的。 – mbmcavoy

0

Here is a blog post of mine with an approach using attached behaviors.

它基于原则是不同枚举值不需要限制切换字符串。相反,您可以声明您想要表示每个值的任何部分(字符串,图像,不同的控件和布局等),并使用附加的行为来控制其可见性。

然后,您的情况可以被定义为具有两个不同的文本块,每个文本块都绑定到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本地化,因为文本像任何其他文本块一样设置。

请参阅the post了解解决方案,代码示例以及包含框架和示例应用程序的zip文件的完整演练。

编辑回应附加信息:

Here is another post in the same series which describes how to select enumeration values with Selector controls.

绑定到ExportRegulationType属性的ComboBox看起来这本:

<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,以便它将回写到视图模型'只要它发生变化,它的财产。

这提供了与文本块相同的灵活性:您可以对如何设置文本以及每个项目包含的内容做出任何决定。

+0

有趣的想法。它并没有真正解决手头的顾虑,但我可以看到它在某些情况下如何派上用场。 – mbmcavoy

+0

@mbmcavoy:您的问题是根据预先设定的解决方案(被Eric Lippert称为“要求薄金属标尺”,http://blogs.msdn.com/b/ericlippert/archive/2003/11/03/一个-parable.aspx)。我确定并解决了您正在尝试解决的问题,友好的枚举名称,并纳入了您的主要要求,在视图模型中没有残留。当然,它不涉及字典绑定,但这不是您的基本目标的固有限制。 –

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> 

这工作完美