在DataGridView上托管自定义控件,从DataTable

时间:2016-05-27 04:20:00

标签: c# .net datagridview cells custom-cell

我有DataGridView,我自动填充数据,如下所示:

MySqlDataAdapter adapter = new MySqlDataAdapter(query, connString);
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
adapter.Fill(table);
e.Result = table;

所以根本没有明确的dataGridView1.Columns.Add()来电。

我希望使特定类型的列托管成为确定的控件,例如,DateTime类型的列必须托管DateTimePicker。虚构的代码示例:

private void dataGridView1_ColumnCreating(object sender, DataGridViewColumnEventArgs e)
{
    if(e.Column.ValueType is DateTime) 
    {
        e.Column = new MyCalendarColumn();
    }
}

或者创建继承自DataGridView的类并添加我自己的列类型支持。

我该怎么做?我已经搜索了在列创建时触发的事件,或者如何通过继承DataGridView左右来添加我自己的列类型。但我只能找到手动添加列而不使用DataTable填充日期的示例。

3 个答案:

答案 0 :(得分:2)

如果您正在寻找MSDN here建议的原生方法,首先您应该将BasicDBObject query = new BasicDBObject() query.put(column_name, new BasicDBObject("$regex", searchString).append("$options", "i")); DBCursor cursor = dbCollection.find(query); cursor.skip((pageNum-1)*limit); cursor.limit(limit); 的{​​{1}}属性设置为AutoGenerateColumns

DataGridView

然后,您需要添加要在此false中显示的列。 (请注意,dataGridView1.AutoGenerateColumns = false; DataGridView以及Id是表格中列的虚构名称,因此请将其更改为实际的列名称:)

Name

请注意,BirthDate是MSDN链接中的一个类。

答案 1 :(得分:1)

我理解了这个问题,你有DataGridView AutoGenerateColumns=true,只需将DataSource属性设置为DataTable,并希望能够自定义自动生成的列。

让我先说明这是不可能的。 DataGridView没有提供任何自定义自动生成列的方法 - 没有事件,虚拟方法,属性等等。它是全部或全部。默认情况下,它只创建3种类型的列 - 复选框,图像和文本,如下所示:

private static DataGridViewColumn DefaultColumnFactory(Type type)
{
    if (type == typeof(bool)) return new DataGridViewCheckBoxColumn(false);
    if (type == typeof(CheckState)) return new DataGridViewCheckBoxColumn(true);
    if (typeof(Image).IsAssignableFrom(type)) return new DataGridViewImageColumn();
    var imageConverter = TypeDescriptor.GetConverter(typeof(Image));
    if (imageConverter.CanConvertFrom(type)) return new DataGridViewImageColumn();
    if (!typeof(System.Collections.IList).IsAssignableFrom(type)) return new DataGridViewTextBoxColumn();
    return null;
}

到目前为止一切顺利。幸运的是,自己构建这个功能并不难。首先,我们将基于上述方法中的属性类型添加另一个“默认”列类型创建。其次,我们将允许调用者“覆盖”每个数据源属性的默认行为,从而启用创建组合框和需要额外初始化的其他类型的列。

为此,我们将其封装在具有以下签名的自定义扩展方法中:

public static void Bind(
    this DataGridView view, 
    object dataSource,
    string dataMember = "", 
    Func<PropertyDescriptor, DataGridViewColumn> columnFactory = null)

dataSourcedataMember代表相应的DataGridView属性,而columnFactory代表是扩展点。

以下是完整的实施:

public static class DataGridViewExtensions
{
    public static void Bind(this DataGridView view, object dataSource, string dataMember = "", Func<PropertyDescriptor, DataGridViewColumn> columnFactory = null)
    {
        var columns = new List<DataGridViewColumn>();
        var properties = ListBindingHelper.GetListItemProperties(dataSource, dataMember, null);
        for (int i = 0; i < properties.Count; i++)
        {
            var property = properties[i];
            if (!property.IsBrowsable) continue;
            var column = (columnFactory != null ? columnFactory(property) : null) ?? DefaultColumnFactory(property.PropertyType);
            if (column == null) continue;
            column.DataPropertyName = property.Name;
            column.Name = property.Name;
            column.HeaderText = !string.IsNullOrEmpty(property.DisplayName) ? property.DisplayName : property.Name;
            column.ValueType = property.PropertyType;
            column.ReadOnly = property.IsReadOnly;
            columns.Add(column);
        }
        view.DataSource = null;
        view.Columns.Clear();
        view.AutoGenerateColumns = false;
        view.Columns.AddRange(columns.ToArray());
        view.DataMember = dataMember;
        view.DataSource = dataSource;
    }

    private static DataGridViewColumn DefaultColumnFactory(Type type)
    {
        if (type == typeof(bool)) return new DataGridViewCheckBoxColumn(false);
        if (type == typeof(CheckState)) return new DataGridViewCheckBoxColumn(true);
        if (typeof(Image).IsAssignableFrom(type)) return new DataGridViewImageColumn();
        var imageConverter = TypeDescriptor.GetConverter(typeof(Image));
        if (imageConverter.CanConvertFrom(type)) return new DataGridViewImageColumn();
        // Begin custom default factory
        if (type == typeof(DateTime)) return new CalendarColumn();
        // End custom default factory
        if (!typeof(System.Collections.IList).IsAssignableFrom(type)) return new DataGridViewTextBoxColumn();
        return null;
    }
}

注意:使用的CalendarColumn来自How to: Host Controls in Windows Forms DataGridView Cells MSDN示例。

上述方法适用于DataTableDataSet以及每种数据源类型(IListIBindingListIListSource等) DataGridView控制。

DataTable的用法就是:

dataGridView.Bind(dataTable);

<强>演示:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        var form = new Form();
        var dg = new DataGridView { Dock = DockStyle.Fill, Parent = form };
        dg.Bind(GetData());
        Application.Run(form);
    }

    static DataTable GetData()
    {
        var dt = new DataTable();
        dt.Columns.AddRange(new[]
        {
            new DataColumn("Id", typeof(int)),
            new DataColumn("Name"),
            new DataColumn("Description"),
            new DataColumn("StartDate", typeof(DateTime)),
            new DataColumn("EndDate", typeof(DateTime)),
        });
        dt.Rows.Add(1, "Foo", "Bar", DateTime.Today, DateTime.Today.AddDays(7));
        return dt;
    }
}

enter image description here

答案 2 :(得分:0)

尝试ColumnAdded事件,看看下面的定义:

public event DataGridViewColumnEventHandler ColumnAdded

将列添加到DataGridView控件时会发生此事件。

以下是一个例子:

private void DataGridView1_ColumnAdded(Object sender, DataGridViewColumnEventArgs e) {

if(e.Column.ValueType is DateTime) {
          e.Column = new MyCalendarColumn();
       }
}

如果有帮助,请告诉我。