【问题标题】:Bind textblock to dictionary value for key in XAML?将文本块绑定到 XAML 中键的字典值?
【发布时间】:2011-11-04 20:07:09
【问题描述】:

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

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

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

两个问题:

1) 在我看来,我应该能够将字典(带有键和值)声明为 XAML 中的静态资源(可能在 App.xaml 中),并将其用于 ComboBox 版本的 ItemsSource。但是,我不知道如何声明和引用这样的东西。我该怎么做?

2) 假设上述内容到位,我想我也可以设置与文本块的绑定,因此基于 enum 属性,它将在字典中查找字符串。

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

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

编辑:附加信息:

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

【问题讨论】:

  • 添加了 C# 作为标签,因此答案得到了语法高亮

标签: c# wpf xaml


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

完美

【讨论】:

    【解决方案2】:

    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 本地化,因为文本的设置与任何其他文本块一样。

    请参阅 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,这样它就会在视图模型的属性发生变化时写回它。

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

    【讨论】:

    • 有趣的想法。它并没有真正解决手头的问题,但我可以看到它如何在某些情况下派上用场。
    • @mbmcavoy:您的问题是用先入为主的解决方案来表达的(Eric Lippert 称为“要求薄金属尺”,blogs.msdn.com/b/ericlippert/archive/2003/11/03/a-parable.aspx)。我确定并解决了您要解决的问题,友好的枚举名称,并结合了您的主要要求,在视图模型中没有杂乱无章。当然,它不涉及字典绑定,但这不是您的基本目标的固有限制。
    【解决方案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.xml 中添加对转换器的引用。 local 是你的类所在的命名空间。

    <local:ExportRegulationTypeToStringConverter x:Key="exportRegConverter" />
    

    最后,设置文本框的值以使用转换器。 pathToEnum 是在您的 ViewModel 上公开的 ExportRegulationType 类型的属性。

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

    使用ObjectDataProvider 用枚举值填充组合框。

    <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>
    

    【讨论】:

    • 我希望我能选择两个答案;我要归功于你在正确的方向上的快速,并且需要更多的代表!
    • 哦,请注意:使用 ComboBox.ItemContainerStyle 几乎可以工作 - 下拉列表中的项目是正确的。但是,选择项目并下拉下拉闭合时,显示了枚举()值。使用数据模板可以正常工作。
    【解决方案4】:

    除了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转换器

    【讨论】:

    • 光滑。作为。见鬼!我喜欢字符串定义嵌入到枚举中,并且转换器(稍作调整)对于任何枚举都是通用的,并且在没有描述属性的情况下是优雅的。
    【解决方案5】:

    使用ObjectDataProvider 然后将 ComboBox 的 Items 绑定到它,并将“DisplayMemberPath”设置为“Value”。

    这应该做的是显示字典的值,但在代码隐藏中 SelectedValueKeyValuePair&lt;&gt;

    对于您的文本块,使用 BindingElementName=yourcomboboxPath=SelectedItem

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

    告诉我进展如何 =)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-09
      • 2017-08-28
      • 2013-07-13
      • 1970-01-01
      • 1970-01-01
      • 2014-07-19
      • 2019-05-28
      • 1970-01-01
      相关资源
      最近更新 更多