【问题标题】:Transposed editable DataGridView转置的可编辑 DataGridView
【发布时间】:2021-01-19 15:32:50
【问题描述】:

我正在尝试按 datagridview 组件中的列绑定我的对象,但我找不到任何方法。
这是我正在努力实现的一个示例。

我有 Emp

public class Emp  
{  
    public int ID { get; set; }  
    public string Name { get; set; }  
    public string City { get; set; }  
  
    public Emp(int id, string name, string city)  
    {  
       this.ID = id;  
       this.Name = name;  
       this.City = city;  
    }  
} 

还有一个 Emp

数组
var arrEmp = new[] {  
    new Emp( 1, "Devesh Omar", "Noida"),  
    new Emp( 2, "Roli", "Kanpur"),  
    new Emp( 3, "Roli Gupta", "Mainpuri"),  
    new Emp( 3, "Roli Gupta", "Kanpur"),  
    new Emp( 3, "Devesh Roli ", "Noida"),  
}; 

当我将数据绑定到网格时

dataGridView1.DataSource = arrEmp; 

我明白了(没关系)

我希望网格只有 3 个固定行(Id、Name、City)和所有值的列。 (矩阵转置) 此外,如果我在 arrEmp 中添加或删除元素,该元素将作为列添加。


示例取自here

【问题讨论】:

  • 没有这样的数据绑定,但你可以手动完成。
  • 我知道,但我想知道是否有任何方法(除了手动),或者是否有实现该功能的组件。
  • 我相信您将不得不手动旋转数据。可能第三方网格控件可能具有此功能。 LINQ 可能会让事情变得更容易,但它仍然是一个手动枢轴。
  • 没有这样的内置方式或内置组件,但是我使用自定义类型描述符做到了。它是可编辑的,当您编辑旋转列表时,您实际上是在编辑原始列表。

标签: c# .net winforms datagridview


【解决方案1】:

没有这样的内置方式或内置组件。

您需要创建自己的组件,或者如果您想为此目的使用 DataGridView,您可以通过编写自定义代码来实现。在这里,我使用自定义 TypeDescriptor 实现了这一点。

类型描述符提供关于类型的信息,包括属性列表以及获取和设置属性值。 DataTable 也以同样的方式工作,为了在 DataGridView 中显示列列表,它返回包含每列属性的属性描述符列表。在这里我使用了这种技术。

正如您在屏幕截图中看到的,当您编辑旋转列表时,您实际上是在编辑原始列表:

//Set Data Source
dgv.DataSource = new RotatedListDataSource<Employee>(list);

//Hide Column Headers
dgv.ColumnHeadersVisible = false;

//Set Row Headers Autosize
dgv.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;

//Show PropertyName on RowHeader
dgv.RowPrePaint += (o, a) =>
{
    var value = ((RotatedItem)dgv.Rows[a.RowIndex].DataBoundItem).PropertyName;
    if (a.RowIndex > -1 && $"{dgv.Rows[a.RowIndex].HeaderCell.Value}" != value)
        dgv.Rows[a.RowIndex].HeaderCell.Value = value;
};

如果你喜欢这个想法,以及为了了解类型描述符的工作原理而尝试一下,这里是我创建的类型描述符和属性描述符的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public class RotatedListDataSource<T> : List<RotatedItem>
{
    public List<T> List { get; }
    public RotatedListDataSource(List<T> list)
    {
        List = list;
        this.AddRange(typeof(T).GetProperties().Select(p =>
            new RotatedItem(
                p.Name,
                list.Cast<object>().ToArray(),
                p.PropertyType)));
    }
}
public class RotatedItem : CustomTypeDescriptor
{
    public string PropertyName { get; }
    private object[] data;
    public Type Type { get; }
    public RotatedItem(string propertyName, object[] data, Type type)
    {
        this.PropertyName = propertyName;
        this.data = data;
        this.Type = type;
    }
    public override PropertyDescriptorCollection GetProperties()
    {
        return this.GetProperties(new Attribute[] { });
    }
    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        var properties = new List<PropertyDescriptor>();
        properties.Add(new PropertyNameProperty(new Attribute[] { 
            new BrowsableAttribute(false)}));
        for (int i = 0; i < data.Length; i++)
        {
            properties.Add(new IndexProperty(i, typeof(object), new Attribute[] { }));
        }
        return new PropertyDescriptorCollection(properties.ToArray());
    }
    public object this[int i]
    {
        get => data[i].GetType().GetProperty(PropertyName).GetValue(data[i]);
        set => data[i].GetType().GetProperty(PropertyName).SetValue(
        data[i], Convert.ChangeType(value, Type));
    }
}
public class IndexProperty : PropertyDescriptor
{
    int index;
    Type type;
    public IndexProperty(int index, Type type, Attribute[] attributes) 
        : base(index.ToString(), attributes)
    {
        this.index = index;
        this.type = type;
    }
    public override Type ComponentType => typeof(RotatedItem);
    public override bool IsReadOnly => false;
    public override Type PropertyType => type;
    public override bool CanResetValue(object component) => false;
    public override object GetValue(object component) => 
       ((RotatedItem)component)[index];
    public override void ResetValue(object component) { }
    public override void SetValue(object component, object value) => 
       ((RotatedItem)component)[index] = value;
    public override bool ShouldSerializeValue(object component) => true;
}
public class PropertyNameProperty : PropertyDescriptor
{
    public PropertyNameProperty(Attribute[] attributes)
        : base(nameof(RotatedItem.PropertyName), attributes) { }
    public override Type ComponentType => typeof(RotatedItem);
    public override bool IsReadOnly => true;
    public override Type PropertyType => typeof(string);
    public override bool CanResetValue(object component) => false;
    public override object GetValue(object component) => 
        ((RotatedItem)component).PropertyName;
    public override void ResetValue(object component) { }
    public override void SetValue(object component, object value) { }
    public override bool ShouldSerializeValue(object component) => true;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    相关资源
    最近更新 更多