发布时间:2023-05-06
Telerik UI for WinForms拥有适用Windows Forms的110多个令人惊叹的UI控件,所有的UI for WinForms控件都具有完整的主题支持,可以轻松地帮助开发人员在桌面和平板电脑应用程序提供一致美观的下一代用户体验。
Telerik UI for WinForms组件为可视化任何类型的数据提供了非常丰富的UI控件,其中RadGridView是最常用的数据组件。在上文中(点击这里回顾>>),我们主要介绍了如何绑定到DataTable、绑定到JSON、绑定到CSV等,本文继续介绍如何层次结构中的多个子选项卡、嵌套多级层次结构等。
获取Telerik UI for Winform R1 2023 SP2下载
Telerik_KendoUI产品技术交流群:726377843 欢迎一起进群讨论
每个GridViewTemplate都有一个Templates属性,用于存储其各自的子层次结构级别。因此,可以在同一层次结构级别上添加尽可能多的子模板。
现在,我们将在Products选项卡旁边添加第二个选项卡,其中包含订单:
DataTable ordersTable = new DataTable(); ordersTable.Columns.Add("OrderID", typeof(int)); ordersTable.Columns.Add("CategoryID", typeof(int)); ordersTable.Columns.Add("OrderDate", typeof(DateTime)); for (int i = 0; i < 30; i++) { ordersTable.Rows.Add(i, rand.Next(0, 5), DateTime.Now.AddDays(-1 * i)); } GridViewTemplate ordersLevel = new GridViewTemplate(); ordersLevel.DataSource = ordersTable; ordersLevel.Caption = "Orders"; ordersLevel.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; this.radGridView1.MasterTemplate.Templates.Add(ordersLevel); GridViewRelation relationOrders = new GridViewRelation(radGridView1.MasterTemplate); relationOrders.ChildTemplate = ordersLevel; relationOrders.RelationName = "CategoriesOrders"; relationOrders.ParentColumnNames.Add("CategoryID"); relationOrders.ChildColumnNames.Add("CategoryID"); this.radGridView1.Relations.Add(relationOrders);
以类似的方式,我们将用必要的GridViewRelations定义嵌套的GridViewTemplates来构造三个层次结构:categories – product – orders。
Random rand = new Random(); DataTable categories = new DataTable(); categories.Columns.Add("CategoryID", typeof(int)); categories.Columns.Add("Title", typeof(string)); categories.Columns.Add("CreatedOn", typeof(DateTime)); for (int i = 0; i < 5; i++) { categories.Rows.Add(i, "Master" + i, DateTime.Now.AddDays(i)); } DataTable productsTable = new DataTable(); productsTable.Columns.Add("ProductID", typeof(int)); productsTable.Columns.Add("CategoryID", typeof(int)); productsTable.Columns.Add("Name", typeof(string)); productsTable.Columns.Add("UnitPrice", typeof(decimal)); for (int i = 0; i < 30; i++) { productsTable.Rows.Add(i, rand.Next(0, 5), "Product" + i, 1.25 * i); } this.radGridView1.MasterTemplate.DataSource = categories; this.radGridView1.MasterTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewTemplate productsLevel = new GridViewTemplate(); productsLevel.DataSource = productsTable; productsLevel.Caption = "Products"; productsLevel.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; this.radGridView1.MasterTemplate.Templates.Add(productsLevel); GridViewRelation relation = new GridViewRelation(radGridView1.MasterTemplate); relation.ChildTemplate = productsLevel; relation.RelationName = "CategoriesProducts"; relation.ParentColumnNames.Add("CategoryID"); relation.ChildColumnNames.Add("CategoryID"); this.radGridView1.Relations.Add(relation); DataTable ordersTable = new DataTable(); ordersTable.Columns.Add("OrderID", typeof(int)); ordersTable.Columns.Add("ProductID", typeof(int)); ordersTable.Columns.Add("OrderDate", typeof(DateTime)); for (int i = 0; i < 100; i++) { ordersTable.Rows.Add(i, rand.Next(0, 30), DateTime.Now.AddDays(-1 * i)); } GridViewTemplate ordersLevel = new GridViewTemplate(); ordersLevel.DataSource = ordersTable; ordersLevel.Caption = "Orders"; ordersLevel.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; productsLevel.Templates.Add(ordersLevel); GridViewRelation relationOrders = new GridViewRelation(productsLevel); relationOrders.ChildTemplate = ordersLevel; relationOrders.RelationName = "ProductsOrders"; relationOrders.ParentColumnNames.Add("ProductID"); relationOrders.ChildColumnNames.Add("ProductID"); this.radGridView1.Relations.Add(relationOrders);
在某些情况下,不需要为所有层次级别加载整个数据,这就是所谓的按需加载功能。只有在被请求时才加载层次结构级别,例如,当用户展开父行时。
private void LoadOnDemand() { Random rand = new Random(); GridViewDecimalColumn idColumn = new GridViewDecimalColumn("CategoryID"); GridViewTextBoxColumn titleColumn = new GridViewTextBoxColumn("Title"); GridViewDateTimeColumn dateColumn = new GridViewDateTimeColumn("CreatedOn"); this.radGridView1.MasterTemplate.Columns.AddRange(idColumn, titleColumn, dateColumn); this.radGridView1.MasterTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; for (int i = 0; i < 5; i++) { this.radGridView1.MasterTemplate.Rows.Add(i, "Master" + i, DateTime.Now.AddDays(i)); } GridViewTemplate productsLevel = new GridViewTemplate(); productsLevel.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill; GridViewDecimalColumn productIdColumn = new GridViewDecimalColumn("ProductID"); GridViewDecimalColumn categoryIdColumn = new GridViewDecimalColumn("CategoryID"); GridViewTextBoxColumn productNameColumn = new GridViewTextBoxColumn("Name"); GridViewDecimalColumn unitPriceColumn = new GridViewDecimalColumn("UnitPrice"); productsLevel.Columns.AddRange(productIdColumn, categoryIdColumn, productNameColumn, unitPriceColumn); this.radGridView1.MasterTemplate.Templates.Add(productsLevel); productsLevel.HierarchyDataProvider = new GridViewEventDataProvider(productsLevel); this.radGridView1.RowSourceNeeded += RadGridView1_RowSourceNeeded; } private void RadGridView1_RowSourceNeeded(object sender, GridViewRowSourceNeededEventArgs e) { if (e.Template.HierarchyLevel==1) { for (int i = 0; i < 30; i++) { GridViewRowInfo row = e.Template.Rows.NewRow(); row.Cells["ProductID"].Value = i; row.Cells["CategoryID"].Value = e.ParentRow.Cells["CategoryID"].Value; row.Cells["Name"].Value = "Product" + row.Cells["CategoryID"].Value+"."+i; row.Cells["UnitPrice"].Value = 1.25 * i; e.SourceCollection.Add(row ); } } }
GridViewRowSourceNeededEventArgs让开发者可以访问相应的模板,因此如果您有几个层次结构级别,可以通过Template.HierarchyLevel或Caption轻松区分他们。
在这篇博文的最后一部分,我们将关注一个非常微妙和重要的问题,即数据绑定和将数据记录的字段与网格列进行映射。当数据记录以与想要使用的RadGridView中相应列不兼容的特定类型存储值时,我们将向您提供如何处理这种情况的技巧。
最常见的情况是在DataSource集合中存储“YES”和“NO”,而GridViewCheckBoxColumn期望布尔值解析true/false值,考虑以下设置:
DataTable dt = new DataTable(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Name", typeof(string)); dt.Columns.Add("IsActive", typeof(string)); for (int i = 0; i < 20; i++) { dt.Rows.Add(i, "Item" + i, i % 2 == 0 ? "YES" : "NO"); } this.radGridView1.DataSource = dt;
默认情况下,RadGridView为字符串字段生成GridViewTextBoxColumn,但是如果想用GridViewCheckBoxColumn替换默认列,则可能会丢失字段值映射,因为字符串值不能解析为布尔值。
为了处理这种情况,我们将实现一个自定义的TypeConverter类,它决定RadGridView如何识别这种类型。
public class ToggleStateConverter : TypeConverter { public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return destinationType == typeof(ToggleState) || destinationType == typeof(bool); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (value is string && destinationType == typeof(ToggleState)) { string stringValue = (string)value; switch (stringValue) { case "YES": return ToggleState.On; case "NO": return ToggleState.Off; default: return ToggleState.Indeterminate; } } else if (value is bool && destinationType == typeof(char)) { bool boolValue = (bool)value; switch (boolValue) { case true: return "YES"; case false: return "NO"; default: return "NO"; } } return base.ConvertTo(context, culture, value, destinationType); } public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(ToggleState) || sourceType == typeof(bool); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { ToggleState state; bool boolValue; if (value is ToggleState) { state = (ToggleState)value; switch (state) { case ToggleState.On: return "YES"; case ToggleState.Off: return "NO"; default: return "NO"; } } else if (value is bool) { boolValue = (bool)value; switch (boolValue) { case true: return "YES"; case false: return "NO"; default: return "NO"; } } return base.ConvertFrom(context, culture, value); } }
现在,对列应用转换器:
DataTable dt = new DataTable(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Name", typeof(string)); dt.Columns.Add("IsActive", typeof(string)); for (int i = 0; i < 20; i++) { dt.Rows.Add(i, "Item" + i, i % 2 == 0 ? "YES" : "NO"); } this.radGridView1.DataSource = dt; this.radGridView1.Columns.Remove("IsActive"); GridViewCheckBoxColumn checkBoxColumn = new GridViewCheckBoxColumn("IsActive"); checkBoxColumn.FieldName = "IsActive"; checkBoxColumn.DataTypeConverter = new ToggleStateConverter(); checkBoxColumn.EditMode = EditMode.OnValueChange; this.radGridView1.Columns.Add(checkBoxColumn);
使用TypeConverter的类似方法可以应用于任何网格列,并且可以转换不同的类型。