簡體   English   中英

在DataGridView上托管自定義控件,從DataTable填充數據

[英]Host custom controls on DataGridView which populate data from DataTable

我有一個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填充日期的示例。

如果你正在尋找一個本地方法,因為通過MSDN建議在這里 ,首先你應該設置AutoGenerateColumns你的財產DataGridViewfalse

dataGridView1.AutoGenerateColumns = false;

然后,您需要添加要在DataGridView顯示的列,如下所示。 (請注意, IdName以及BirthDate是表中列的虛構名稱,因此請將它們更改為實際的列名稱):

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

DataGridViewColumn(table.Columns[0].ColumnName, new DataGridViewTextBoxColumn());
DataGridViewColumn(table.Columns[1].ColumnName, new DataGridViewTextBoxColumn());
DataGridViewColumn(table.Columns[2].ColumnName, new DataGridViewTextBoxColumn());
DataGridViewColumn(table.Columns[3].ColumnName, new CalendarColumn());//Create the CalendarColumn class as MSDN suggested


private void DataGridViewColumn(string colName, DataGridViewColumn colType)
{
    colType.DataPropertyName = colName;
    colType.HeaderText = colName;
    colType.Name = colName;
    dataGridView1.Columns.Add(colType);
}

請注意, CalendarColumn是MSDN鏈接中的一個類。

據我所知,你有一個AutoGenerateColumns=trueDataGridView ,只需將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來自如何:Windows窗體DataGridView Cells MSDN示例中的主機控件

上述方法適用於DataTableDataSet以及DataGridView控件支持的每種數據源類型( IListIBindingListIListSource等)。

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

在此輸入圖像描述

嘗試ColumnAdded事件,看看下面的定義:

public event DataGridViewColumnEventHandler ColumnAdded

將列添加到DataGridView控件時會發生此事件。

這是一個例子:

private void DataGridView1_ColumnAdded(Object sender, DataGridViewColumnEventArgs e) {

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

如果這有幫助,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM