将文本块绑定到XAML中键的字典值?

时间:2011-08-26 20:40:42

标签: c# wpf xaml

我有一个带枚举属性的模型(在这种情况下,与出口管制法规相关)。当向用户显示值时,我想显示相应的字符串。有时这是在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属性,它将在字典中查找字符串。

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

这些应该只是一个XAML,并且可以让我从ViewModel中删除方法(只有一个公开的ExportRegulationType枚举属性。这些可能吗?

编辑:其他信息:

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

5 个答案:

答案 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”。

这应该是显示字典的值,但在代码隐藏中,SelectedValueKeyValuePair<>

对于您的文本块,请使用Binding ElementName=yourcomboboxPath=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

编辑以回复其他信息:

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

绑定到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,这样只要它发生变化,它就会回写到视图模型的属性。

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