DataTemplate 是 WPF 豐富 UI 客製化的核心技術。雖然通常在 XAML 定義,但動態編輯欄位、新增列等情境需透過程式碼建立。本文示範如何使用 FrameworkElementFactory 在 C# 中完整構建 DataTemplate。
典型 ListView 的 GridViewColumn CellTemplate 定義:
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding Path=IsSelected}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
GridViewColumn column = new GridViewColumn();
GridViewColumnHeader header = new GridViewColumnHeader();
header.Content = "選擇";
header.Tag = "IsSelected";
column.Header = header;
// 建立 DataTemplate
DataTemplate dt = new DataTemplate();
FrameworkElementFactory fef = new FrameworkElementFactory(typeof(CheckBox));
// 設定綁定
Binding binding = new Binding();
binding.Path = new PropertyPath("IsSelected");
fef.SetBinding(CheckBox.IsCheckedProperty, binding);
// 設定屬性
fef.SetValue(CheckBox.HorizontalAlignmentProperty, HorizontalAlignment.Center);
fef.SetValue(CheckBox.ForegroundProperty, Brushes.White);
// 指定視覺樹根節點
dt.VisualTree = fef;
column.CellTemplate = dt;
// 加入 GridView
(this.lvExecutionTable.View as GridView).Columns.Add(column);
{Binding ...},第一參數為目標相依性屬性,第二參數為 Binding 物件若 DataTemplate 包含多層元素(如 Border 包含 TextBlock),需設定根元素的 ContentProperty 或 ChildProperty:
// 根元素:Border
FrameworkElementFactory borderFactory = new FrameworkElementFactory(typeof(Border));
borderFactory.SetValue(Border.BackgroundProperty, Brushes.LightBlue);
borderFactory.SetValue(Border.CornerRadiusProperty, new CornerRadius(3));
borderFactory.SetValue(Border.PaddingProperty, new Thickness(5));
// 子元素:TextBlock
FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBlock));
Binding textBinding = new Binding("Name");
textFactory.SetBinding(TextBlock.TextProperty, textBinding);
textFactory.SetValue(TextBlock.ForegroundProperty, Brushes.DarkBlue);
// 將 TextBlock 設為 Border 的 Child
borderFactory.AppendChild(textFactory);
DataTemplate dt = new DataTemplate();
dt.VisualTree = borderFactory;
使用 AppendChild 建立父子關係,可構建任意深度的視覺樹結構。
FrameworkElementFactory 為唯讀不可變更,建立後不可修改,需一次設定完成DataTemplateSelector 或載入 XAML 字串 (XamlReader.Load) 以獲得更佳維護性