首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WPF 動態模板選擇器:DataTemplateSelector 實戰指南

     編輯:關於.NET

前言

當資料項目需根據屬性值或全域狀態動態套用不同 DataTemplate 時,DataTemplateSelector 是最佳解決方案。本文透過兩個完整範例 (XML 資料綁定與硬體偵測狀態) 示範如何實作自訂 Template Selector,並搭配資源字典管理多樣化模板。

核心概念

DataTemplateSelector 為抽象類別,僅需覆寫 SelectTemplate(object item, DependencyObject container) 方法,依邏輯回傳對應 DataTemplate。容器參數可用於 FindResource 尋找具名模板。

範例一:依 XML 元素名稱選擇模板 (書籍/CD/DVD)

1. 定義 Template Selector

public class LocalNameTemplateSelector : DataTemplateSelector {
    public override DataTemplate SelectTemplate(object item, DependencyObject container) {
        XmlElement data = item as XmlElement;
        if (data != null) {
            return ((FrameworkElement)container).FindResource(data.LocalName) as DataTemplate;
        }
        return null;
    }
}

2. 定義三種模板 (資源字典)

<DataTemplate x:Key="Book" DataType="{x:Type sx:XmlElement}">
    <StackPanel Orientation="Horizontal">
        <Rectangle Margin="2" Width="14" Height="14" Fill="Brown"/>
        <TextBlock VerticalAlignment="Center" Text="{Binding XPath=@Title}"/>
    </StackPanel>
</DataTemplate>
<DataTemplate x:Key="CD" DataType="{x:Type sx:XmlElement}">
    <StackPanel Orientation="Horizontal">
        <Ellipse Margin="2" Width="14" Height="14" Fill="Silver"/>
        <TextBlock VerticalAlignment="Center" Text="{Binding XPath=@Title}"/>
    </StackPanel>
</DataTemplate>
<DataTemplate x:Key="DVD" DataType="{x:Type sx:XmlElement}">
    <StackPanel Orientation="Horizontal">
        <Ellipse Margin="2" Width="14" Height="14" Fill="Blue"/>
        <TextBlock VerticalAlignment="Center" Text="{Binding XPath=@Title}"/>
    </StackPanel>
</DataTemplate>

3. 綁定 XML 資料源與 ListBox

<Window x:Class="WpfProgressBarDemo.DataTemplateSelectorDemo"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sx="clr-namespace:System.Xml;assembly=System.Xml"
        Title="DataTemplateSelector" Height="300" Width="300"
        DataContext="{DynamicResource dataSource}">
    <Window.Resources>
        <XmlDataProvider x:Key="dataSource">
            <x:XData>
                <Media xmlns="">
                    <Book Author="Aretch" Title="WCF全面解析"/>
                    <Book Author="ByVoid" Title="Node.js開發指南"/>
                    <Book Author="Rogers Cardenhead" Title="21天學通Java"/>
                    <CD Title="沒有CD了"/>
                    <DVD Title="《十面埋伏》"/>
                </Media>
            </x:XData>
        </XmlDataProvider>
        <!-- 上述三個 DataTemplate 放這裡 -->
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding XPath=/Media/*}">
            <ListBox.ItemTemplateSelector>
                <l:LocalNameTemplateSelector xmlns:l="clr-namespace:WpfProgressBarDemo"/>
            </ListBox.ItemTemplateSelector>
        </ListBox>
    </Grid>
</Window>

範例二:依硬體偵測結果 (布林值) 切換成功/失敗模板

1. Template Selector 邏輯

public class LocalNameTemplateSelector : DataTemplateSelector {
    public override DataTemplate SelectTemplate(object item, DependencyObject container) {
        if (item != null && item is DeviceCheckInfo) {
            DeviceCheckInfo device = item as DeviceCheckInfo;
            Window2 win = new Window2(); // 注意:實務上應避免 new Window,改用 Application.Current.FindResource 或傳入容器
            if (device.CheckResult) return win.FindResource("dui") as DataTemplate;
            else return win.FindResource("cuo") as DataTemplate;
        }
        return null;
    }
}
public class DeviceCheckInfo {
    public string Name { get; set; }
    public string CheckContent { get; set; }
    public bool CheckResult { get; set; }
}

2. 定義成功/失敗模板 (含自繪 Path 圖示)

<Window.Resources>
    <DataTemplate x:Key="dui" DataType="{x:Type local:DeviceCheckInfo}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Name}" Margin="10" VerticalAlignment="Center" FontSize="20"/>
            <TextBlock Text="{Binding Path=CheckContent}" Margin="10" VerticalAlignment="Center" FontSize="20"/>
            <Path x:Name="dui" Data="M43,5 L20,40 20,40 0,20 6,15 18,26 37,7 43,5 z"
                  Fill="Green" Margin="5" Stretch="Fill"/>
            <CheckBox Name="checkbox" />
        </StackPanel>
    </DataTemplate>
    <DataTemplate x:Key="cuo" DataType="{x:Type local:DeviceCheckInfo}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Name}" Margin="10" VerticalAlignment="Center" FontSize="20"/>
            <TextBlock Text="{Binding Path=CheckContent}" Margin="10" VerticalAlignment="Center" FontSize="20"/>
            <Path Margin="5" Data="M50,25 L25,50 M25,25 50,50"
                  Fill="#FFF4F4F5" Height="40" Stretch="Fill" Stroke="Red" Width="40" StrokeThickness="8"/>
            <CheckBox Name="checkbox" />
        </StackPanel>
    </DataTemplate>
    <local:LocalNameTemplateSelector x:Key="myDataTemplateSelector"/>
</Window.Resources>

3. ListBox 套用 Selector

<ListBox Name="lbtest" ItemTemplateSelector="{StaticResource myDataTemplateSelector}" />

進階提示:DataTrigger 替代方案

若切換邏輯單純 (如依單一屬性值),也可在 DataTemplate 內使用 DataTrigger 切換 ContentTemplate 或直接修改視覺樹屬性,無需撰寫 Selector 類別。但 Selector 更適合複雜邏輯、跨專案重用、單元測試。

總結

DataTemplateSelector 讓 WPF 列表控件擁有「根據資料動態換裝」的能力。配合資源字典集中管理模板、FindResource 動態載入,能構建極具彈性的 UI 呈現層。本文兩個範例分別展示 XML 元素名稱與布林屬性兩種常見選擇依據,涵蓋從資料綁定到視覺化的完整鏈路。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved