【问题标题】:Automatically generating DataGrid column from enum从枚举自动生成 DataGrid 列
【发布时间】:2014-07-23 20:28:59
【问题描述】:

我正在使用 WPF DataGrid 控件的列自动生成功能。其中一列是选择列 - 基于一些枚举。

枚举看起来像这样:

public enum MyTypes {
  Integer = 1,
  Float = 2
  IntegerArray = 3,
  FloatArray = 4
}

我想将array 类型不显示为 IntegerArray、FloatArray,而是显示为 Integer[], Float[] 在自动生成的下拉列表中。

换句话说 - 单元格将包含一个下拉列表,其中包含值 Integer、Float、IntegerArray、FloatArray,我希望它们是 Integer、Float、Integer[]、Float[]。显然我不能在 MyTypes 声明中将 IntegerArray 更改为 Integer[]。

我该怎么做?

编辑:

Pushpray 在下面的回答仅部分起作用-我得到枚举字段描述(因此,我得到 Float[] 而不是在 ComboBox 中使用 FloatArr,但是当持有ComboBox 的列失去焦点时,我得到 @ 987654326@.

【问题讨论】:

  • 我不关注。您想为您的枚举值显示不同的值吗?所以单元格应该包含字符串'Float[]'?
  • 是的,这就是我想要实现的目标。单元格将包含一个下拉列表,其值为IntegerFloatIntegerArrayFloatArray,我希望它们为IntegerFloatInteger[]Float[]。显然,我不能在我的 MyTypes 声明中将 IntegerArray 更改为 Integer[]

标签: c# wpf datagrid enums


【解决方案1】:

这是我提供的解决您问题的方法

结果

我们首先将所需的值定义为枚举值的Description 属性

public enum MyTypes
{
    Integer = 1,
    Float = 2,
    [Description("Integer[]")]
    IntegerArray = 3,
    [Description("Float[]")]
    FloatArray = 4
}

然后创建一个类,该类具有从枚举类型中枚举列表的方法,如果应用该枚举类型将考虑 Description 属性

namespace CSharpWPF
{
    public class EnumHelper
    {
        public static IEnumerable<string> GetEnumDescriptions(Type enumType)
        {
            foreach (var item in Enum.GetNames(enumType))
            {
                FieldInfo fi = enumType.GetField(item);

                DescriptionAttribute[] attributes =
                    (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attributes != null && attributes.Length > 0)
                    yield return attributes[0].Description;
                else
                    yield return item;
            }
        }
    }
}

最后使用ObjectDataProvider使用EnumHelper类中的枚举器方法GetEnumDescriptions,并使用与DataGridComboBoxColumn的ItemsSource相同的源

样本 xaml

<DataGrid xmlns:l="clr-namespace:CSharpWPF">
    <DataGrid.Columns>
        <DataGridComboBoxColumn Header="EnumValues" >
            <DataGridComboBoxColumn.ItemsSource>
                <Binding>
                    <Binding.Source>
                        <ObjectDataProvider MethodName="GetEnumDescriptions"
                                            ObjectType="{x:Type l:EnumHelper}">
                            <ObjectDataProvider.MethodParameters>
                                <x:Type TypeName="l:MyTypes" />
                            </ObjectDataProvider.MethodParameters>
                        </ObjectDataProvider>
                    </Binding.Source>
                </Binding>
            </DataGridComboBoxColumn.ItemsSource>
        </DataGridComboBoxColumn>
    </DataGrid.Columns>
</DataGrid>

与自动生成列一起使用

<DataGrid x:Name="dGrid" 
          AutoGenerateColumns="True" 
          AutoGeneratingColumn="DataGrid_OnAutoGeneratingColumn"
          xmlns:l="clr-namespace:CSharpWPF">
    <DataGrid.Resources>
        <l:EnumHelper x:Key="EnumHelper" />
        <ObjectDataProvider x:Key="EnumValues"
                            MethodName="GetEnumDescriptions"
                            ObjectType="{x:Type l:EnumHelper}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="l:MyTypes" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
        <DataTemplate x:Key="MyTypesCellTemplate">
            <TextBlock Text="{Binding EnumValue, Converter={StaticResource EnumHelper}}"/>
        </DataTemplate>
        <DataTemplate x:Key="MyTypesCellEditingTemplate">
            <ComboBox  SelectedItem="{Binding EnumValue, Converter={StaticResource EnumHelper}}"
                ItemsSource="{Binding Source={StaticResource EnumValues}}" />
        </DataTemplate>
    </DataGrid.Resources>
</DataGrid>

事件处理程序

    private void DataGrid_OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.PropertyType == typeof(MyTypes))
        {
            DataGridTemplateColumn templateColumn = new DataGridTemplateColumn();
            templateColumn.Header = e.Column.Header;
            templateColumn.CellTemplate = (DataTemplate)dGrid.Resources["MyTypesCellTemplate"];
            templateColumn.CellEditingTemplate = (DataTemplate)dGrid.Resources["MyTypesCellEditingTemplate"];
            e.Column = templateColumn;
        }
    }

EnumHelper 类

public class EnumHelper : IValueConverter
{
    public static IEnumerable<string> GetEnumDescriptions(Type enumType)
    {
        foreach (var item in Enum.GetNames(enumType))
        {
            FieldInfo fi = enumType.GetField(item);

            DescriptionAttribute[] attributes =
                (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attributes != null && attributes.Length > 0)
                yield return attributes[0].Description;
            else
                yield return item;
        }
    }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return string.Empty;

        FieldInfo fi = value.GetType().GetField(value.ToString());

        DescriptionAttribute[] attributes =
            (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attributes != null && attributes.Length > 0)
            return attributes[0].Description;
        else
            return value.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return MyTypes.Float;

        Type enumType = typeof(MyTypes);
        foreach (var item in Enum.GetNames(enumType))
        {
            FieldInfo fi = enumType.GetField(item);

            DescriptionAttribute[] attributes =
                (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attributes != null && attributes.Length > 0 && string.Equals(attributes[0].Description, value))
                return Enum.Parse(enumType, item);
        }
        return Enum.Parse(enumType, value.ToString());
    }
}

演示

这是基于上述答案的工作示例代码

DataGridEnumsSample.zip (VS 2013)

MD5 校验和:9C34BB81857C78375582FAC0E1C8A95D

【讨论】:

  • 但是我的列是自动生成的,所以我怎样才能让你的机制在我的情况下工作? DatagridItemsSource 属性绑定到 List&lt;Class with informations about columns, and one of those is Enum&gt;
  • 你可能会定义相同的数据模板并在列生成时对其进行自定义,请参阅How to: Customize Auto-Generated Columns in the DataGrid Control
  • 好的,我稍后试试,如果可行,请接受你的回答
  • 刚刚我回到了这个项目,但发生了一些不好的事情 - 我可以从组合框中选择值,但是当持有组合框的字段失去焦点时,我立即得到异常 - NullReferenceException as如果没有设置值
  • 如果您发现难以将此解决方案合并到您的项目中。您可以做的是使用上面的解决方案创建新的测试项目并查看它是如何工作的,然后您将更容易与您的项目合并。我相信你不会错过任何重要的事情。
【解决方案2】:

我有另一个解决方案,它允许您使用自动生成的列在DataGrid 中显示枚举。这适用于使用反射创建的枚举类型。

首先,创建一个继承自DataGridBoundColumnEnumTemplateColumn

public class EnumTemplateColumn : DataGridBoundColumn
{
    private readonly Type enumType;

    public EnumTemplateColumn(Type enumType)
    {
        this.enumType = enumType;
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        string columnHeader = cell.Column.Header.ToString();
        TextBlock textBlock = new TextBlock();
        var dataRowView = (DataRowView) dataItem;
        var enumValue = dataRowView[columnHeader];

        textBlock.Text = Enum.GetName(this.enumType, enumValue);

        return textBlock;
    }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        throw new NotImplementedException();
    }
}

接下来,使用DataGridOnAutoGeneratingColumn事件来使用EnumTemplateColumn

    private void DataGrid_OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.PropertyType.IsEnum)
        {
            e.Column = new EnumTemplateColumn(e.PropertyType)
            {
                Header = e.Column.Header,
            };
        }
    }

还有 WPF 组件:

    <DataGrid x:Name="dataGrid"
              Grid.Row="5" 
              ItemsSource="{Binding Path=DataTable}" IsReadOnly="True"
              AutoGeneratingColumn="DataGrid_OnAutoGeneratingColumn"/>

【讨论】:

    【解决方案3】:

    我是这样做的:在DataGridAutoGeneratingColumnevent 中,将默认的DataGridComboBoxColumn 替换为DataGridTextColumn,并手动添加绑定和转换器。

        private void dataGrid1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            if (e.PropertyType.IsEnum)
            {
                //(e.Column as DataGridComboBoxColumn)
    
                var col = new DataGridTextColumn
                {
                    Header = e.PropertyName
                };
    
                col.Binding = new Binding(e.PropertyName)
                {
                    Converter = new WPFCommon.BindingConverters.EnumConverter()
                };
    
                // Replace the auto-generated column with the new one.
                e.Column = col;
            }
        }
    

    转换器类,

    namespace WPFCommon.BindingConverters
    {
        public class EnumConverter:IValueConverter
        {
            //** this does not work for enum value in DataTable
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value == null || string.IsNullOrEmpty(value.ToString()))
                    return DependencyProperty.UnsetValue;
    
                return ((Enum)value).GetDescription();
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return value;
            }
        }
    }
    

    枚举扩展类,

    public static class EnumExtensions
    {
        public static string GetDisplayName(this Enum enu)
        {
            DisplayAttribute attr = GetDisplayAttribute(enu);
            return attr != null ? attr.Name : enu.ToString();
        }
    
        public static string GetDescription(this Enum enu)
        {
            DescriptionAttribute attr = GetDescriptionAttribute(enu);
            return attr != null ? attr.Description : enu.ToString();
        }
    
        private static DescriptionAttribute GetDescriptionAttribute(object value)
        {
            Type type = value.GetType();
            if (!type.IsEnum)
            {
                throw new ArgumentException(string.Format("Type {0} is not an enum", type));
            }
    
            // Get the enum field.
            var field = type.GetField(value.ToString());
            return field == null ? null : field.GetCustomAttribute<DescriptionAttribute>();
        }
    
        private static DisplayAttribute GetDisplayAttribute(object value)
        {
            Type type = value.GetType();
            if (!type.IsEnum)
            {
                throw new ArgumentException(string.Format("Type {0} is not an enum", type));
            }
    
            // Get the enum field.
            var field = type.GetField(value.ToString());
            return field == null ? null : field.GetCustomAttribute<DisplayAttribute>();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-04
      • 1970-01-01
      • 2021-01-04
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 2014-03-12
      • 1970-01-01
      相关资源
      最近更新 更多