在 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
的 class 并添加我自己的列类型支持。
我该怎么做?我已经搜索了在列创建时触发的事件或如何通过继承 DataGridView
左右来添加我自己的列类型。但我只能找到手动添加列而不是使用 DataTable
.
填充日期的示例
试试 ColumnAdded 事件,看看下面的定义:
public event DataGridViewColumnEventHandler ColumnAdded
将列添加到 DataGridView
控件时发生此事件。
这是一个例子:
private void DataGridView1_ColumnAdded(Object sender, DataGridViewColumnEventArgs e) {
if(e.Column.ValueType is DateTime) {
e.Column = new MyCalendarColumn();
}
}
如果有帮助请告诉我。
如果您正在寻找 MSDN here 建议的本机方法,首先您应该将 DataGridView
的 AutoGenerateColumns
属性 设置为 false
:
dataGridView1.AutoGenerateColumns = false;
然后您需要像这样添加要在 DataGridView
中显示的列。 (请注意 Id
和 Name
和 BirthDate
是您 table 中列的虚构名称,因此请将它们更改为您的实际列名称):
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 link.
中的 class
据我了解,您有一个 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;
}
到目前为止一切顺利。幸运的是,我们自己构建该功能并不难。首先,我们将在上述方法中添加另一个基于 属性 类型的 "default" 列类型创建。其次,我们将允许调用者 "override" 每个数据源的默认行为 属性,从而允许创建需要额外初始化的组合框和其他类型的列。
为此,我们将其封装在具有以下签名的自定义扩展方法中:
public static void Bind(
this DataGridView view,
object dataSource,
string dataMember = "",
Func<PropertyDescriptor, DataGridViewColumn> columnFactory = null)
dataSource
和dataMember
代表对应的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 示例。
上述方法适用于 DataTable
、DataSet
以及支持的所有数据源类型(IList
、IBindingList
、IListSource
等)由 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;
}
}
我有一个 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
的 class 并添加我自己的列类型支持。
我该怎么做?我已经搜索了在列创建时触发的事件或如何通过继承 DataGridView
左右来添加我自己的列类型。但我只能找到手动添加列而不是使用 DataTable
.
试试 ColumnAdded 事件,看看下面的定义:
public event DataGridViewColumnEventHandler ColumnAdded
将列添加到 DataGridView
控件时发生此事件。
这是一个例子:
private void DataGridView1_ColumnAdded(Object sender, DataGridViewColumnEventArgs e) {
if(e.Column.ValueType is DateTime) {
e.Column = new MyCalendarColumn();
}
}
如果有帮助请告诉我。
如果您正在寻找 MSDN here 建议的本机方法,首先您应该将 DataGridView
的 AutoGenerateColumns
属性 设置为 false
:
dataGridView1.AutoGenerateColumns = false;
然后您需要像这样添加要在 DataGridView
中显示的列。 (请注意 Id
和 Name
和 BirthDate
是您 table 中列的虚构名称,因此请将它们更改为您的实际列名称):
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 link.
据我了解,您有一个 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;
}
到目前为止一切顺利。幸运的是,我们自己构建该功能并不难。首先,我们将在上述方法中添加另一个基于 属性 类型的 "default" 列类型创建。其次,我们将允许调用者 "override" 每个数据源的默认行为 属性,从而允许创建需要额外初始化的组合框和其他类型的列。
为此,我们将其封装在具有以下签名的自定义扩展方法中:
public static void Bind(
this DataGridView view,
object dataSource,
string dataMember = "",
Func<PropertyDescriptor, DataGridViewColumn> columnFactory = null)
dataSource
和dataMember
代表对应的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 示例。
上述方法适用于 DataTable
、DataSet
以及支持的所有数据源类型(IList
、IBindingList
、IListSource
等)由 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;
}
}