测试原因:
拟在asp.net下进行数据统计,数据传递给silverlight进行显示。统计数据来源是多张表通过数组动态产生相应的列并将统计数据存储显示,用SQL的说法就是把行改为列,不知道这样描述是否好理解一些。。由于silverlight 不支持dataset与datatable所以尝试在网上找相关的替代方法,未果,尝试自己实现相应的方法。
测试环境:vs2010 silverlight5 radchontrols treelistview Version:2012.2.912.1050
说明:
说穿了就是动态绑定列,未发现技术难度。在下面的DEMO中不涉及asp.net 至silverlight的数据传递,萝卜白菜各有所爱,有太多的方法可以实现,这里不增加代码阅读难度,仅就动态绑定列给出相应DEMO.
代码:演示代码采用了radcontrols下treelistview的相关代码
1、创建绑定树所用类
public class WarehouseItem { public WarehouseItem(string name, int count) { this.Name = name; this.Count = count; this.Items = new ObservableCollection<WarehouseItem>(); //为了方便演示,在这里直接进行了初始化 Columns = new Dictionary<string, int>(); Columns.Add("x", 0); Columns.Add("a", 1); Columns.Add("b", 2); Columns.Add("c", 3); } public string Name { get; set; } //这是绑定树用的集合 public ObservableCollection<WarehouseItem> Items { get; set; } public int Count { get; set; } //这就是用来绑定列的集合 public Dictionary<string, int> Columns { get; set; } }
2、集合赋值,这个没什么可说的,是直接拷贝radcontrols的代码,列的初始化我放到了上面
public class WarehouseService { public static ObservableCollection<WarehouseItem> GetWarehouseData() { ObservableCollection<WarehouseItem> data = new ObservableCollection<WarehouseItem>(); WarehouseItem drinks = new WarehouseItem("Drinks", 35); drinks.Items.Add(new WarehouseItem("Water", 10)); WarehouseItem tea = new WarehouseItem("Tea", 20); tea.Items.Add(new WarehouseItem("Black", 10)); tea.Items.Add(new WarehouseItem("Green", 10)); drinks.Items.Add(tea); drinks.Items.Add(new WarehouseItem("Coffee", 5)); data.Add(drinks); WarehouseItem vegetables = new WarehouseItem("Vegeatbles", 75); vegetables.Items.Add(new WarehouseItem("Tomato", 40)); vegetables.Items.Add(new WarehouseItem("Carrot", 25)); vegetables.Items.Add(new WarehouseItem("Onion", 10)); data.Add(vegetables); WarehouseItem fruits = new WarehouseItem("Fruits", 55); fruits.Items.Add(new WarehouseItem("Cherry", 30)); fruits.Items.Add(new WarehouseItem("Apple", 20)); fruits.Items.Add(new WarehouseItem("Melon", 5)); data.Add(fruits); return data; } }
3、mainpage的xaml代码
<UserControl xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="SilverlightApplication1.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <telerik:RadTreeListView x:Name="radTreeListView" AutoGenerateColumns="False"> <telerik:RadTreeListView.ChildTableDefinitions> <telerik:TreeListViewTableDefinition ItemsSource="{Binding Items}"/> </telerik:RadTreeListView.ChildTableDefinitions> </telerik:RadTreeListView> </Grid> </UserControl>
4、代码动态绑定列
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); LoadData(); } private void LoadData() { radTreeListView.Columns.Add(new Telerik.Windows.Controls.GridViewDataColumn() { DataMemberBinding=new System.Windows.Data.Binding("Name"), Header="名称" }); radTreeListView.Columns.Add(new Telerik.Windows.Controls.GridViewDataColumn() { DataMemberBinding = new System.Windows.Data.Binding("Count"), Header = "数量" }); ObservableCollection<WarehouseItem> objItmes = WarehouseService.GetWarehouseData(); //获取列头信息 Dictionary<string, int> colItems = objItmes[0].Columns; //列头循环绑定 foreach (var item in colItems) { System.Windows.Data.Binding bind= new System.Windows.Data.Binding(""); bind.Mode=System.Windows.Data.BindingMode.OneTime; bind.Source=item.Value; radTreeListView.Columns.Add(new Telerik.Windows.Controls.GridViewDataColumn() { DataMemberBinding=bind, Header = item.Key }); } this.radTreeListView.ItemsSource = objItmes; }
重点就是红字这块,看着很简单,当时实现却花了不少时间。主要是自己对silverlight的应用还不是很熟练。在CSDN上提出这个问题也没有得到解决,所以写下这个记录备忘,也给其他需要实现类似功能的朋友提供帮助。
2012.09.26
在使用中发现这种方法绑定的列数值是全部一样的,如果想绑定不同的数值则此方法无法正常实现,在网上搜索半天找到下面这篇文章,通过对原文代码进行修改,实现最终功能
《Silverlight DataGrid – Populate Dynamic Columns from a Child Collection》
radcontrol实现代码如下:
集合类增加调整用测试数据
public static ObservableCollection<WarehouseItem> GetWarehouseData() { ObservableCollection<WarehouseItem> data = new ObservableCollection<WarehouseItem>(); WarehouseItem drinks = new WarehouseItem("Drinks", 35); drinks.Columns.Clear(); drinks.Columns.Add("x",2); drinks.Columns.Add("a", 5); drinks.Columns.Add("b", 9); drinks.Columns.Add("c", 3);
mainpage的绑定修改
private void LoadData() { radTreeListView.Columns.Add(CreateTextColumn("Name", "名称")); radTreeListView.Columns.Add(CreateTextColumn("Count", "数量")); ObservableCollection<WarehouseItem> objItmes = WarehouseService.GetWarehouseData(); //获取列头信息 Dictionary<string, int> colItems = objItmes[0].Columns; //列头循环绑定 foreach (var item in colItems) { radTreeListView.Columns.Add(CreateTemplateColumn(item.Key,item.Key)); } this.radTreeListView.ItemsSource = objItmes; } private static GridViewDataColumn CreateTextColumn(string fieldName, string title) { GridViewDataColumn column = new GridViewDataColumn(); column.Header = title; column.DataMemberBinding = new System.Windows.Data.Binding(fieldName); return column; } private GridViewDataColumn CreateTemplateColumn(string key, string title) { GridViewDataColumn column = new GridViewDataColumn(); column.Header = title; column.CellTemplate = (DataTemplate)XamlReader.Load(CreateColumnTemplate(key)); //display template return column; } private string CreateColumnTemplate(string key) { StringBuilder CellTemp = new StringBuilder(); CellTemp.Append("<DataTemplate "); CellTemp.Append("xmlns='http://schemas.microsoft.com/winfx/"); CellTemp.Append("2006/xaml/presentation' "); CellTemp.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>"); // 这里要注意红色部分需要与集合的名称相同
CellTemp.Append(String.Format("<TextBlock Text='{{Binding Columns[{0}]}}'/>", key)); CellTemp.Append("</DataTemplate>"); return CellTemp.ToString(); }