转置可编辑DataGridView [英] Transposed editable DataGridView

查看:51
本文介绍了转置可编辑DataGridView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过datagridview组件中的列绑定我的对象,但找不到任何方法.
这是我要达到的目标的一个例子.

我有 Emp

 公共类Emp{public int ID {get;放;}公共字符串名称{get;放;}公共字符串City {get;放;}公共Emp(int id,字符串名称,字符串城市){this.ID = id;this.Name =名称;this.City = city;}} 

和一组 Emp

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

当我将数据绑定到网格上

  dataGridView1.DataSource = arrEmp; 

我明白了(没关系)

我希望网格只有3个固定行(Id,Name,City),而列中的所有值都是.(矩阵转置)另外,如果我向arrEmp添加元素或从arrEmp中删除元素,则该元素将作为列添加.


该示例取自

 //设置数据源dgv.DataSource = new RotatedListDataSource< Employee>(列表);//隐藏列标题dgv.ColumnHeadersVisible = false;//设置行标题的自动大小dgv.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;//在RowHeader上显示PropertyNamedgv.RowPrePaint + =(o,a)=>{var value =(((RotatedItem)dgv.Rows [a.RowIndex] .DataBoundItem).PropertyName;if(a.RowIndex> -1&& $"{dgv.Rows [a.RowIndex] .HeaderCell.Value}"!=值)dgv.Rows [a.RowIndex] .HeaderCell.Value =值;}; 

如果您喜欢这个主意,可以尝试一下以了解类型描述符的工作原理,那么这里是我创建的类型描述符和属性描述符的代码:

 使用系统;使用System.Collections.Generic;使用System.ComponentModel;使用System.Linq;公共类RotatedListDataSource< T>:列表< RotatedItem>{公共列表< T>列出{get;}公共RotatedListDataSource(List< T>列表){列表=列表;this.AddRange(typeof(T).GetProperties().Select(p =>新的RotatedItem(p.名称,list.Cast< object>().ToArray(),p.PropertyType)));}}公共类RotatedItem:CustomTypeDescriptor{公共字符串PropertyName {get;}私有对象[]数据;公共类型类型{get;}公共RotatedItem(字符串propertyName,object []数据,Type类型){this.PropertyName = propertyName;this.data =数据;this.Type =类型;}公共重写PropertyDescriptorCollection GetProperties(){返回this.GetProperties(new Attribute [] {});}公共重写PropertyDescriptorCollection GetProperties(Attribute []属性){var properties = new List< PropertyDescriptor>();properties.Add(new PropertyNameProperty(new Attribute [] {new BrowsableAttribute(false)}));对于(int i = 0; i< data.Length; i ++){properties.Add(new IndexProperty(i,typeof(object),new Attribute [] {}));}返回新的PropertyDescriptorCollection(properties.ToArray());}公共对象this [int i]{得到=>data [i] .GetType().GetProperty(PropertyName).GetValue(data [i]);设置=>数据[i] .GetType().GetProperty(PropertyName).SetValue(数据[i],Convert.ChangeType(value,Type));}}公共类IndexProperty:PropertyDescriptor{整数索引类型类型;public IndexProperty(int索引,类型类型,Attribute []属性):base(index.ToString(),属性){this.index =索引;this.type =类型;}公共重写类型ComponentType =>typeof(RotatedItem);公共替代布尔IsReadOnly =>错误的;公共重写类型PropertyType =>类型;公共替代布尔值CanResetValue(object component)=>错误的;公共替代对象GetValue(对象组件)=>(((RotatedItem)组件)[index];公共重写void ResetValue(对象组件){}公共重写void SetValue(对象组件,对象值)=>(((RotatedItem)component)[index] = value;公共重写bool ShouldSerializeValue(object component)=>真的;}公共类PropertyNameProperty:PropertyDescriptor{公共PropertyNameProperty(Attribute []属性):base(nameof(RotatedItem.PropertyName),属性){}公共重写类型ComponentType =>typeof(RotatedItem);公共替代布尔IsReadOnly =>真的;公共重写类型PropertyType =>typeof(字符串);公共替代布尔值CanResetValue(object component)=>错误的;公共替代对象GetValue(对象组件)=>((RotatedItem)组件).PropertyName;公共重写void ResetValue(对象组件){}公共重写void SetValue(对象组件,对象值){}公共重写bool ShouldSerializeValue(object component)=>真的;} 

I am trying to bind my objects by columns in the datagridview component but I could not find any way to do it.
This is an example of what I am trying to achieve.

I have the Emp class

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

and an array of 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"),  
}; 

When I bind the data to the grid

dataGridView1.DataSource = arrEmp; 

I get this (which is ok)

I would like that the grid has only 3 fixed rows (Id, Name, City) and the column all the values. (the matrix transpose) Also, if I add or remove an element to/from arrEmp, that the element will be added as a column.


The example was taken from here

解决方案

There's not such a built-in way or built-in component for that.

You need to create your own component, or if you want to use DataGridView for that purpose, you can achieve it by writing custom code. Here I've achieved that using a custom TypeDescriptor.

Type descriptor provide information about type, including list of properties and getting and setting property values. DataTable also works the same way, to show list of columns in DataGridView, it returns a list of property descriptors containing properties per column. Here I've used such technique.

As you can see in the screen capture, when you edit the rotated list, you are actually editing the original list:

//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;
};

If you liked the idea and what to give it a try for learning purpose to see how type descriptor works, here is the code for type descriptor and property descriptors that I created:

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

这篇关于转置可编辑DataGridView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆