c# Wpf 将枚举绑定(bind)到组合框

标签 c# wpf enums combobox binding

我在将 WeekDay 枚举绑定(bind)到组合框时遇到问题。 nutritionPlan 绑定(bind)效果很好。

这是我的 .xaml 代码:

<Page x:Class="WpfApp.Views.AddDailyNutritionPlan"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:local="clr-namespace:WpfApp.Views"
  mc:Ignorable="d" 
  d:DesignHeight="450" d:DesignWidth="800"
    Title="AddDailyNutritionPlan">
<Grid Background="#A4EE6A" >
    <ComboBox Name="cmbnutritionplan" ItemsSource="{Binding NutritionPlans}" 
              HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="119,36,0,0">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding NutritionPlanName}" />
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
    <ComboBox Name="cmbweekday" ItemsSource="{Binding Path=WeekDays}" HorizontalAlignment="Left" 
              VerticalAlignment="Top" Width="120" Margin="119,72,0,0" RenderTransformOrigin="1.701,0.613">

    </ComboBox>
</Grid>

最佳答案

如果您希望能够从您的 XAML 中简单地绑定(bind)一个枚举,您可以编写一个标记扩展类。我前段时间写了一篇关于它的博客文章: http://simonkatanski.blogspot.com/2013/02/enum-combobox-using-markupextension.html

代码如下:

public class EnumValuesExtension : MarkupExtension
{
    private Type _enumType;
    private String _resourceName;
    private bool _addEmptyValue = false;
    // Enumeration type
    public Type EnumType
    {
        set { _enumType = value; }
    }
    // Name of the class of the .resx file        
    public String ResourceName
    {
        set { _resourceName = value; }
    }
    // Add empty value flag        
    public Boolean AddEmptyValue
    {
        set { _addEmptyValue = value; }
    }
    public EnumValuesExtension()
    {
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        // Enumeration type not passed through XAML
        if (_enumType == null)
            throw new ArgumentNullException("EnumType (Property not set)");
        if (!_enumType.IsEnum)
            throw new ArgumentNullException("Property EnumType must be an enum");
        // Bindable properties list
        List<dynamic> list = new List<dynamic>();

        if (!String.IsNullOrEmpty(_resourceName))
        {
            // Name of the resource class
            Type type = Type.GetType(_resourceName);
            if (type == null)
                throw new ArgumentException(
                    "Resource name should be a fully qualified name");
            // We iterate through the Enum values
            foreach (var enumName in Enum.GetNames(_enumType))
            {
                string translation = string.Empty;
                var property = type.GetProperty(enumName,
                    BindingFlags.Static |
                    BindingFlags.Public |
                    BindingFlags.NonPublic);
                // If there's not translation for specific Enum value,
                // there'll be a message shown instead
                if (property == null)
                    translation = String.Format(
                        "Field {0} not found in the resource file {1}",
                        enumName,
                        _resourceName);
                else
                    translation = property.GetValue(null, null).ToString();

                list.Add(GetNamed(translation, enumName));
            }
            // Adding empty row
            if (_addEmptyValue)
                list.Add(GetEmpty());
            return list;
        }
        // If there's no resource provided Enum values will be used
        // without translation
        foreach (var enumName in Enum.GetNames(_enumType))
            list.Add(GetNamed(enumName, enumName));

        if (_addEmptyValue)
            list.Add(GetEmpty());

        return list;
    }

    // Create one item which will fill our ComboBox ItemSource list
    private dynamic GetNamed(string translation, string enumName)
    {
        // We create a bindable context
        dynamic bindableResult = new ExpandoObject();
        // This dynamically created property will be
        // bindable from XAML (through DisplayMemberPath or wherever)
        bindableResult.Translation = translation;
        // We're setting the value, which will be passed to SelectedItem
        // of the ComboBox
        bindableResult.Enum = enumName;
        return bindableResult;
    }

    // Create one empty item which will fill our ComboBox ItemSource list
    private dynamic GetEmpty()
    {
        dynamic bindableResult = new ExpandoObject();
        bindableResult.Translation = String.Empty;
        bindableResult.Enum = null;
        return bindableResult;
    }
}

您可以像这样在您的代码中使用此类:

<StackPanel>
<ComboBox Height="100" Width="200"
          SelectedValuePath="Enum" 
          DisplayMemberPath="Translation"
          ItemsSource="{Binding Source={local:EnumValues EnumType=local:TestEnum}}"
          Margin="98,0,76,0"
          SelectedValue="{Binding SelectedItemInYourViewModel}"/>
</StackPanel>

然后您所做的就是将您的枚举作为上述 xaml 中的枚举类型传递。通过这种方式,您可以通过一种通用方式使用 xaml 中的枚举。

我在这里粘贴的版本和博客中的版本有额外的代码用于热切换值及其翻译的等价物(如果你正在开发多语言应用程序) - 你应该能够轻松删除它代码。

关于c# Wpf 将枚举绑定(bind)到组合框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50658353/

相关文章:

c# - wpf 列表框给列一个标题

wpf - 带有图像的 RichTextBox - 行距问题

c++ - 将 QObject 连接指定为唯一的正确方法是什么?

c# - XNA/C# 世界矩阵中的 2D 坐标缩放到 3D View 矩阵?

c# - 如何在我的 Visual Studio 集成包 (VSPackage) 中制作单独的菜单?

c# - C# 中 Exception.Data 可以为 null 吗?

创建一个接受枚举变量并返回字符串指针的函数

c# - 结合 struct 和 new() 泛型类型约束

c# - WPF C# - 使用 Xaml 加载图像文件夹

c# - 遍历枚举?