如何在DataGridView中填充自定义列单元格

本文关键字:自定义 单元格 填充 DataGridView | 更新日期: 2023-09-27 18:15:25

我设法向DGV添加另一列,但现在我在用值填充单元格时遇到了麻烦。

到目前为止我写的是:

// add new column
int lineItemsColumnIndex = dataGridView1.Columns.Add("LineItems", "Line Items");
// set up nested DataGridView for orders and lineitems.
foreach (DataGridViewRow row in dataGridView1.Rows)
{
    List<LineItem> lineItems = ((Order)(row.DataBoundItem)).lineItems;
    string cellValue = "";
    for(int i=0; i<lineItems.Count; i++){
        FoodMenuItem menuItem = new FoodMenuItem(lineItems[i].menuItemID);
        cellValue += lineItems[i].quantity.ToString() + "x " + menuItem.title + (i==lineItems.Count-1 ? "." : ", ");
    }
    row.Cells[lineItemsColumnIndex].Value = cellValue;
}

如何将数据放入自定义列?

如何在DataGridView中填充自定义列单元格

应该是这样的…

您确定代码运行时DGV已经有行了吗?

但是你还可以考虑另一件事:

你可以为你的数据对象创建包装器,和/或添加一个自定义类型描述符,为你的数据添加一个新的属性,可以被。net数据绑定使用,这样你就不必手动设置列了…

像这样:

public class Wrapper<T> : System.ComponentModel.ICustomTypeDescriptor 
    {
        public T wrappee { get; private set; }
        private Dictionary<String, Func<T, String>> ext_get;
        public Wrapper(T theObjectWeWantToWrap,Dictionary<String,Func<T,String>> theSpecsForTheAdditionalColumns)
        {
            wrappee = theObjectWeWantToWrap;
            ext_get = theSpecsForTheAdditionalColumns;
        }
        System.ComponentModel.AttributeCollection System.ComponentModel.ICustomTypeDescriptor.GetAttributes()
        {
            return TypeDescriptor.GetAttributes(wrappee,true);
        }
        string System.ComponentModel.ICustomTypeDescriptor.GetClassName()
        {
            return TypeDescriptor.GetClassName(wrappee, true);
        }
        string System.ComponentModel.ICustomTypeDescriptor.GetComponentName()
        {
            return TypeDescriptor.GetComponentName(wrappee, true);
        }
        System.ComponentModel.TypeConverter System.ComponentModel.ICustomTypeDescriptor.GetConverter()
        {
            return TypeDescriptor.GetConverter(wrappee, true);
        }
        System.ComponentModel.EventDescriptor System.ComponentModel.ICustomTypeDescriptor.GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(wrappee, true);
        }
        System.ComponentModel.PropertyDescriptor System.ComponentModel.ICustomTypeDescriptor.GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(wrappee, true);
        }
        object System.ComponentModel.ICustomTypeDescriptor.GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(wrappee, editorBaseType, true);
        }
        System.ComponentModel.EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(wrappee, attributes, true);
        }
        System.ComponentModel.EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
        {
            return TypeDescriptor.GetEvents(wrappee, true);
        }
        System.ComponentModel.PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            return filterProps(TypeDescriptor.GetProperties(wrappee, attributes, true));
        }
        System.ComponentModel.PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties()
        {
            return filterProps(TypeDescriptor.GetProperties(wrappee, true));
        }
        object System.ComponentModel.ICustomTypeDescriptor.GetPropertyOwner(System.ComponentModel.PropertyDescriptor pd)
        {
            if (ext_get.Keys.Contains(pd.Name))
                return this;
            return wrappee;
        }
        private PropertyDescriptorCollection filterProps(PropertyDescriptorCollection propertyDescriptorCollection)
        {
            List<PropertyDescriptor> pd_list = new List<PropertyDescriptor>(propertyDescriptorCollection.Cast<PropertyDescriptor>().Where(x=>!ext_get.Keys.Contains(x.DisplayName)));
            foreach (var item in ext_get)
            {
                pd_list.Add(new MyPropertyDescriptor<T>(item));
            }
            return new PropertyDescriptorCollection(pd_list.ToArray());
        }
        private class MyPropertyDescriptor<T> : System.ComponentModel.PropertyDescriptor 
        {
            public MyPropertyDescriptor(KeyValuePair<string,Func<T,string>>kvp)
                :base(kvp.Key,new Attribute[]{})
            {
                f = kvp.Value;
            }
            private Func<T, String> f;
            public override bool CanResetValue(object component)
            {
                return false;
            }
            public override Type ComponentType
            {
                get { return typeof(Wrapper<T>); }
            }
            public override object GetValue(object component)
            {
                Wrapper<T> c = (Wrapper<T>)component;
                return f(c.wrappee);
            }
            public override bool IsReadOnly
            {
                get { return true; }
            }
            public override Type PropertyType
            {
                get { return typeof(String); }
            }
            public override void ResetValue(object component)
            {
                throw new NotImplementedException();
            }
            public override void SetValue(object component, object value)
            {
                throw new NotImplementedException();
            }
            public override bool ShouldSerializeValue(object component)
            {
                return false;
            }
        }
    }

可以这样使用:

    List<DataClass> list = new List<DataClass>();
    list.Add(new DataClass());
    Dictionary<string, Func<DataClass, String>> ext = new Dictionary<string, Func<DataClass, string>>();
    ext["New Column"] = (DataClass x) => String.Join(" ,", x.Items.ToArray());
    List<Wrapper<DataClass>> list2 = new List<Wrapper<DataClass>>(list.Select(x=>new Wrapper<DataClass>(x,ext)));
    class1DataGridView.DataSource = list2;

添加列后,在DataBindingComplete事件中执行如下操作:

foreach (DataGridViewRow row in dgv.Rows)
{if (row.Cells[7].Value.ToString()=="1")
row.Cells[0].Value = "number one"; }

(只是一个愚蠢的例子来说明)

,但记住它必须在DataBindingComplete(或从一个按钮点击等),否则它将保持空白