WPF中動態創建DataTemplate


眾所周知,在WPF中,我們可以使用DataTemplate靈活地設計UI來呈現綁定的數據,對於不同數據,我們還可以使用DataTemplateSelector選擇不同的DataTemplate。但是有時候,這還不能滿足需求。這又要說到我正在開發的服裝DRP,這並非打廣告,而是我闡述的知識點都是在實際項目中碰到的,而且通過項目也好說明問題。

系統中有個報表叫下級訂單分布,列出下級機構的訂單量,如圖:

其中訂單量相關的單元格中的數字表示的含義:黑色數字表示剩余訂單量,紅色上標數字表示總訂單量-已發貨量。毫無疑問,這需要DataTemplate來實現。問題是下級機構的數量是不定的,即GridView綁定的數據列數是不一定的,幾個到幾百個都有可能(DataTemplateSelector就用不着考慮了),因此我們不能用實體類集合作為綁定數據源(動態增加屬性,雖說C#4.0的動態特性大大增強了,但畢竟不是真正的動態語言,使用起來頗為不便,效率還挺低),而只能用DataTable/DataView,並且要動態地指定每個訂單列的DataTemplate。假如使用實體類,那么訂單列可以綁定到某個復雜屬性(包含剩余訂單量、總訂單量、已發貨量),這樣DataTemplate只要在xaml中定義一次就可以了。但是既然使用的是DataTable,而DataTable假如從數據庫獲取的話,它的每一列的數據類型一般都是基本類型(復雜類型沒試過,目測DataColumn只支持基礎類型(錯誤,DataColumn支持復雜類型,且前端XAML綁定可寫成“ColumnName.PropertyName”)),動態創建DataTemplate就必不可少了。

關於動態創建DataTemplate,我參考了WPF中使用C#程序代碼創建DataTemplate數據模版的方法。代碼如下: 

 1 private void btnSearch_Click(object sender, RoutedEventArgs e)  2 {  3     while (gv.Columns.Count > 5)  4         gv.Columns.RemoveAt(5);  5     var data = _dataContext.GetSubordinateOrderDistribution();  6     bool showAll = rbAllOrder.IsChecked.Value;  7     if (!showAll)  8         data.RemoveAll(o => o.QuaDelivered == o.Quantity);  9     DataTable table = new DataTable(); 10     table.Columns.Add(new DataColumn("ProductCode", typeof(string))); 11     table.Columns.Add(new DataColumn("BrandCode", typeof(string))); 12     table.Columns.Add(new DataColumn("StyleCode", typeof(string))); 13     table.Columns.Add(new DataColumn("ColorCode", typeof(string))); 14     table.Columns.Add(new DataColumn("SizeName", typeof(string))); 15     var onames = data.Select(o => o.OrganizationName).Distinct().ToList(); 16     onames.Add("合計"); 17     foreach (var on in onames) 18  { 19         table.Columns.Add(new DataColumn(on, typeof(int))); 20         table.Columns.Add(new DataColumn("delivered" + on, typeof(int))); 21         table.Columns.Add(new DataColumn("all" + on, typeof(int))); 22         //gv.Columns.Add(new GridViewDataColumn() { Header = on, Name = on, DataMemberBinding = new Binding(on) });
23         var col = new GridViewDataColumn() { Header = on, Name = on, DataMemberBinding = new Binding(on) }; 24         //內存中動態生成一個XAML,描述了一個DataTemplate
25         XNamespace ns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; 26         XElement xGrid = new XElement(ns + "Grid", new XElement(ns + "Grid.ColumnDefinitions", new XElement(ns + "ColumnDefinition", new XAttribute("Width", "Auto")), new XElement(ns + "ColumnDefinition", new XAttribute("Width", "Auto")))); 27         xGrid.Add(new XElement(ns + "TextBlock", new XAttribute("Text", "{Binding Path=" + on + "}"), new XAttribute("Margin", "0 0 5 0"))); 28         if (showAll) 29  { 30  xGrid.Add( 31                 new XElement(ns + "TextBlock", new XAttribute("Foreground", "Red"), new XAttribute("Text", "{Binding Path=" + "delivered" + on + "}"), new XAttribute("FontSize", "8"), new XAttribute("Grid.Column", "1"))); 32  } 33         else
34  { 35  xGrid.Add( 36                 new XElement(ns + "TextBlock", new XAttribute("Foreground", "Red"), new XAttribute("FontSize", "8"), new XAttribute("Grid.Column", "1"), 37                 new XElement(ns + "TextBlock", new XAttribute("Text", "{Binding Path=" + "all" + on + "}")), 38                 new XElement(ns + "TextBlock", new XAttribute("Text", "-")), 39                 new XElement(ns + "TextBlock", new XAttribute("Text", "{Binding Path=" + "delivered" + on + "}")))); 40  } 41         XElement xDataTemplate = new XElement(ns + "DataTemplate", new XAttribute("xmlns", "http://schemas.microsoft.com/winfx/2006/xaml/presentation")); 42  xDataTemplate.Add(xGrid); 43         XmlReader xr = xDataTemplate.CreateReader(); 44         DataTemplate dataTemplate = XamlReader.Load(xr) as DataTemplate; 45         col.CellTemplate = dataTemplate; 46  gv.Columns.Add(col); 47  } 48     var ps = data.OrderBy(o => o.ProductCode).Select(o => o.ProductID).Distinct(); 49     foreach (var p in ps) 50  { 51         var d = data.First(o => o.ProductID == p); 52         DataRow row = table.NewRow(); 53  table.Rows.Add(row); 54         row["ProductCode"] = d.ProductCode; 55         row["BrandCode"] = d.BrandCode; 56         row["StyleCode"] = d.StyleCode; 57         row["ColorCode"] = d.ColorCode; 58         row["SizeName"] = d.SizeName; 59         foreach (var on in onames) 60  { 61             if (on == "合計") 62  { 63                 var totalData = data.Where(o => o.ProductID == p); 64                 var quantity = totalData.Sum(o => o.Quantity); 65                 var quaDelivered = totalData.Sum(o => o.QuaDelivered); 66                 row[on] = showAll ? quantity : (quantity - quaDelivered); 67                 row["all" + on] = quantity; 68                 row["delivered" + on] = quaDelivered; 69                 continue; 70  } 71             d = data.Find(o => o.ProductID == p && o.OrganizationName == on); 72             if (d != null) 73  { 74                 row[on] = showAll ? d.Quantity : (d.Quantity - d.QuaDelivered); 75                 row["all" + on] = d.Quantity; 76                 row["delivered" + on] = d.QuaDelivered; 77  } 78  } 79  } 80     gv.ItemsSource = table.DefaultView; 81 }

 注意最后ItemsSource設置成DefaultView,如果直接用DataTable那么CellTemplate的Binding就有問題,無法綁定,不知何故。另外XElement xDataTemplate = new XElement(ns + "DataTemplate", new XAttribute("xmlns", http://schemas.microsoft.com/winfx/2006/xaml/presentation)); ns和xmlns屬性聲明都不能忽略,否則會報錯。

轉載請注明本文出處:http://www.cnblogs.com/newton/archive/2012/12/13/2816753.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM