【问题标题】:Dynamic way of generating columns in wpf datagrid using mvvm使用 mvvm 在 wpf 数据网格中生成列的动态方法
【发布时间】:2016-11-23 11:56:02
【问题描述】:

我想使用 mvvm 动态生成一个数据网格。在数据网格的每个单元格中,我必须显示一个对象。列名是对象的属性之一。数据网格的 Itemsource 将是 object 列表。如何使用mvvm动态生成datagrid?

更新

我创建了一个使用 ICustomTypeDescriptor 扩展的自定义类。

    public class MyCustomType : ICustomTypeDescriptor
    {
    // This is instance data.
    private readonly BindingList<PropertyDescriptor> _propertyDescriptors = new BindingList<PropertyDescriptor>();

    // The data is stored on the type instance.
    private readonly IDictionary<string, object> _propertyValues = new Dictionary<string, object>();

    // The property descriptor now takes an extra argument.
    public void AddProperty(string name, Type type)
    {
        _propertyDescriptors.Add(new MyPropertyDescriptor(name, type));
    }

    public PropertyDescriptorCollection GetProperties()
    {
        return new PropertyDescriptorCollection(_propertyDescriptors.ToArray());
    }

    public PropertyDescriptorCollection GetProperties(Type type)
    {
        return new PropertyDescriptorCollection(_propertyDescriptors.ToArray());
    }

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        return GetProperties();
    }

    public object GetPropertyOwner(PropertyDescriptor pd)
    {
        throw new NotImplementedException();
    }

    public AttributeCollection GetAttributes()
    {
        throw new NotImplementedException();
    }

    public string GetClassName()
    {
        throw new NotImplementedException();
    }

    public string GetComponentName()
    {
        throw new NotImplementedException();
    }

    public TypeConverter GetConverter()
    {
        throw new NotImplementedException();
    }

    public EventDescriptor GetDefaultEvent()
    {
        throw new NotImplementedException();
    }

    public PropertyDescriptor GetDefaultProperty()
    {
        throw new NotImplementedException();
    }

    public object GetEditor(Type editorBaseType)
    {
        throw new NotImplementedException();
    }

    public EventDescriptorCollection GetEvents()
    {
        return null;
    }

    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return null;
    }

    private class MyPropertyDescriptor : PropertyDescriptor
    {
        // This data is here to indicate that different instances of the type
        // object may have properties of the same name, but with different
        // characteristics.
        private readonly Type _type;

        public MyPropertyDescriptor(string name, Type type)
            : base(name, null)
        {
            _type = type;
        }

        public override bool CanResetValue(object component)
        {
            throw new NotImplementedException();
        }

        public override Type ComponentType
        {
            get { throw new NotImplementedException(); }
        }

        public override object GetValue(object component)
        {
            MyCustomType obj = (MyCustomType) component;
            object value = null;
            obj._propertyValues.TryGetValue(Name, out value);
            return value;
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override Type PropertyType
        {
            get { return _type; }
        }

        public override void ResetValue(object component)
        {
            throw new NotImplementedException();
        }

        public override void SetValue(object component, object value)
        {
            var oldValue = GetValue(component);

            if (oldValue != value)
            {
                MyCustomType obj = (MyCustomType) component;
                obj._propertyValues[Name] = value;
                OnValueChanged(component, new PropertyChangedEventArgs(Name));
            }
        }

        public override bool ShouldSerializeValue(object component)
        {
            throw new NotImplementedException();
        }

        public override void AddValueChanged(object component, EventHandler handler)
        {
            // set a breakpoint here to see WPF attaching a value changed handler
            base.AddValueChanged(component, handler);
        }
    }
}

我正在将此 customtype 对象的列表绑定到 datagrid itemsource。但是datagrid没有显示任何内容?

【问题讨论】:

    标签: c# wpf mvvm datagrid


    【解决方案1】:

    使用 DataGrid 的方法是将IEnumerable&lt;T&gt; 作为其 ItemsSource,其中 T 是具有您希望为其生成列的属性的类或接口。您应该使用 DataGrid 支持的类型。支持大多数值类型。你可以找到一个列表HERE关于支持的类型以及用法。

    所以您的列表应该包含行的对象,而不是单元格的对象。 DataGrid 将为列表的通用参数类型的每个公共属性自动生成单元格。

    然后您可以使用 MVVM 来绑定列表,如下所示:

    <DataGrid ItemsSource="{Binding MyList}" AutoGenerateColumns="True"></DataGrid>
    

    当然,DataGrid 的 DataContext(继承的或显式的)应该包含带有项目的 public IEnumerable&lt;T&gt; MyList { get; }

    更新

    实际上每个行对象依次都有单元格的对象列表。 每个单元格对象都有多个属性。我想显示 1 个 属性值作为列名,每个单元格对象将有不同的 基于对象类型的单元格样式。如何动态创建 有这么多条件的数据网格?

    在 WPF 中,DataGrid 为每一行设置了相同的列。因此,在您的情况下,即使您可以为每个单元格定义不同的列数据,也只能使用第一行(或您需要的行)来定义列。我宁愿建议创建Custom Attributes 以声明列属性(数据类型、标题..等),因为它是声明性信息而不是动态信息(不应该从行到行或不时更改)。通过使用THIS 线程中描述的触发器,样式信息仍然可以具有一些活力。这更像是一种 WPF 方式。

    无论如何,如果您想坚持您的架构,您应该在派生自 DataGrid 的类中实现列探索逻辑。在 ItemsSourceChanged 处理程序中,您检查 ItemsSource 的类型。如果那是一个 IEnumerable,则您可以通过反射获取通用参数 (T),并检查该类型是否支持您描述架构的列。比如:

    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
    {
        base.OnItemsSourceChanged(oldValue, newValue);
    
        if (AutoGenerateColumns && newValue != null && newValue.GetType().IsGenericType)
        {
            this.Columns.Clear();
    
            var type = newValue.GetType().GetGenericArguments().First();
    
            if (typeof(IMyColumnDescriptionStructure).IsAssignableFrom(type))
            {
                var rows = newValue as IEnumerable<IMyColumnDescriptionStructure>;
                var firstRow = rows.First() as IMyColumnDescriptionStructure;
    
                // TODO: explore your structure and add column definitions
                ///this.Columns.Add(...)
            }
        }
    }
    

    【讨论】:

    • 谢谢丹尼尔,实际上每个行对象依次都有单元格的对象列表。每个单元格对象都有多个属性。我想将属性值的 1 显示为列名,并且每个单元格对象将根据对象的类型具有不同的单元格样式。这么多条件如何动态创建数据网格?
    猜你喜欢
    • 2016-05-12
    • 2014-09-04
    • 2013-11-18
    • 2014-10-11
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2015-02-01
    相关资源
    最近更新 更多