1. 程式人生 > >WPF Template模版之DataTemplate與ControlTemplate【一】

WPF Template模版之DataTemplate與ControlTemplate【一】

    WPF系統不但支援傳統的Winfrom程式設計的使用者介面和使用者體驗設計,更支援使用專門的設計工具Blend進行專業設計,同時還推出了以模板為核心的新一代設計理念。

1. 模板的內涵

  作為表現形式,每個控制元件都是為了實現某種使用者操作演算法和直觀顯示某種資料而生,一個控制元件看上去是什麼樣子由它的“演算法內容”和“資料內容"決定,這就是內容決定形式,這裡,我們引入兩個概念:

控制元件的演算法內容:控制元件能展示哪些資料、具有哪些方法、能響應哪些操作、能激發什麼事件,簡而言之就是控制元件的功能,它們是一組相關的演算法邏輯。
控制元件的資料內容:控制元件具體展示的資料是什麼。


     以往的GUI開發技術(ASP.NET+Winform)中,控制元件內部邏輯和資料是固定的,程式設計師不能改變;對於控制元件的外觀,程式設計師能做的改變也非常的有限,一般也就是設定控制元件的屬性,想改變控制元件的內部結構是不可能的。如果想擴充套件一個控制元件的功能或者更改器外觀讓其更適應業務邏輯,哪怕只是一丁點的改變,也需要建立控制元件的子類或者建立使用者控制元件。造成這個局面的根本原因是資料和演算法的“形式”和“內容”耦合的太緊了。


    在WPF中,通過引入模板,微軟將資料和演算法的內容與形式解耦了。WPF中的Template分為兩大類:
ControlTemplate:是演算法內容的表現形式,一個控制元件怎麼組織其內部結構才能讓它更符合業務邏輯、讓使用者操作起來更舒服就是由它來控制的。它決定了控制元件“長成什麼樣子”,並讓程式設計師有機會在控制元件原有的內部邏輯基礎上擴充套件自己的邏輯。
DataTemplate:是資料內容的展示方式,一條資料顯示成什麼樣子,是簡單的文字還是直觀的圖形就由它來決定了。


Template就是資料的外衣-----ControlTemplate是控制元件的外衣,DataTemplate是資料的外衣。

2. 資料的外衣DataTemplate

    WPF不但支援UserControl還支援DataTemplate為資料形成檢視。不要以為DataTemplate有多難!從UserControl升級到DataTemplate一般就是複製,貼上一下再改幾個字元的事兒。

DataTemplate常用的地方有三處,分別是:
ContentControl的ContentTemplate屬性,相當於給ContentControl的內容穿衣服。
ItemsControl的ItemTemplate,相當於給ItemControl的資料條目穿衣服。
GridViewColumn的CellTempldate屬性,相當於給GridViewColumn的資料條目穿衣服。



    事件驅動是控制元件和控制元件之間溝通或者說是形式和形式之間的溝通,資料驅動則是資料與控制元件之間的溝通,是內容決定形式。使用DataTemplate就可以方便的把事件驅動模式轉換為資料驅動模式。

    讓我們用一個例子體現DataTemplate的使用。例子實現的需求是這樣的:有一列汽車資料,這列資料顯示在ListBox裡面,要求ListBox的條目顯示汽車的廠商圖示和簡要引數,單擊某個條目後在窗體的詳細內容區顯示汽車的圖片和詳細引數。廠商的Logo和汽車的照片都是要用到的,所以先在專案中建立資源管理目錄並把圖片新增進來。Logo檔名與廠商的名稱一致,照片的名稱則與車名一致。組織結構如圖:


建立Car資料型別:

/// <summary>
/// Car資料型別 -- 必須定義成屬性{ get; set; }
/// </summary>
public class Car
{
    public string Name { get; set; }
    public string ImagePath { get; set; }
    public string Automarker { get; set; }
    public string Year { get; set; }
}

汽車廠商和名稱不能直接拿來作為圖片路徑,這時就要使用Converter:

/// <summary>
    /// 路徑轉圖片
    /// </summary>
    public class PathToImage:IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string url = (string)value;
            return(new BitmapImage(new Uri(url, UriKind.Relative)));
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

XAML中新增條目模版:

        <DataTemplate x:Key="_carListItemViewTemplate">
            <Grid Margin="2">
                <StackPanel Orientation="Horizontal">
                    <Image Source="{Binding Path=Automarker, Converter={StaticResource _path2Image}}" Grid.RowSpan="3"
                           Width="64" Height="64"></Image>
                    <StackPanel Margin="5,10">
                        <TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold"></TextBlock>
                        <TextBlock Text="{Binding Year}" FontSize="14"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </DataTemplate>
XAML中新增顯示詳細資訊的模版:
        <DataTemplate x:Key="_carDetailViewTemplate">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6">
                <StackPanel Margin="5">
                    <Image Width="400" Height="250" Source="{Binding Path=ImagePath, Converter={StaticResource _path2Image}}"></Image>
                    <StackPanel Orientation="Horizontal" Margin="5, 0">
                        <TextBlock Text="Name:" FontWeight="Bold" FontSize="20"></TextBlock>
                        <TextBlock Text="{Binding Path=Name}" FontSize="20" Margin="5, 0"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
完整的XAML程式碼:
<Window x:Class="WpfApplication11.wnd112"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication11"
        Title="DataTemplate" Height="350" Width="623">
    <Window.Resources>
        <!--Convert-->
        <local:PathToImage x:Key="_path2Image"></local:PathToImage>
        <!--DataTemplate for Detail View -->
        <DataTemplate x:Key="_carDetailViewTemplate">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6">
                <StackPanel Margin="5">
                    <Image Width="400" Height="250" Source="{Binding Path=ImagePath, Converter={StaticResource _path2Image}}"></Image>
                    <StackPanel Orientation="Horizontal" Margin="5, 0">
                        <TextBlock Text="Name:" FontWeight="Bold" FontSize="20"></TextBlock>
                        <TextBlock Text="{Binding Path=Name}" FontSize="20" Margin="5, 0"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
        <!--DataTemplate for Item View -->
        <DataTemplate x:Key="_carListItemViewTemplate">
            <Grid Margin="2">
                <StackPanel Orientation="Horizontal">
                    <Image Source="{Binding Path=Automarker, Converter={StaticResource _path2Image}}" Grid.RowSpan="3"
                           Width="64" Height="64"></Image>
                    <StackPanel Margin="5,10">
                        <TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold"></TextBlock>
                        <TextBlock Text="{Binding Year}" FontSize="14"></TextBlock>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Window.Resources>    
    <!---Window Content-->
    <StackPanel Orientation="Horizontal" Margin="5">
        <UserControl ContentTemplate="{StaticResource _carDetailViewTemplate}" Content="{Binding Path=SelectedItem, ElementName=_listBoxCars}"></UserControl>
        <ListBox x:Name="_listBoxCars" Width="180" Margin="5,0" ItemTemplate="{StaticResource _carListItemViewTemplate}"></ListBox>
    </StackPanel>
</Window>

    程式碼對於初學者來說有點長但是結構非常簡單。其中最重要的有兩句:
ContentTemplate="{StaticResource _carDatialViewTemplate}",相當於給一個普通的UserControl穿上了一件外衣、讓Car資料以圖文並茂的方式展現出來。這件外衣就是x:Key="_carDatialViewTemplate"標記的DataTemplate資源。
ItemTemplate="{StaticResource _listBoxCars}",把每一件資料的外衣交給ListBox,當ListBox的ItemSource被賦值的時候,ListBox就會為每個條目穿上這件外衣。這件外衣是以x:Key="_listBoxCars"標記的DataTemplate資源。
因為不再使用事件驅動,而且為資料穿衣服的事也已經自動完成,所以後臺的C#程式碼就非常的簡單。窗體的C#程式碼就只剩下這些:
    /// <summary>
    /// wnd112.xaml 的互動邏輯
    /// </summary>
    public partial class wnd112 : Window
    {
        List<Car> _carList;
        public wnd112()
        {
            InitializeComponent();

            _carList = new List<Car>()
            {
                new Car(){Name = "Aodi1", [email protected]"/Resources/Images/Aodi.jpg", [email protected]"/Resources/Images/01077_1.png", Year="1990"},
                new Car(){Name = "Aodi2", [email protected]"/Resources/Images/Aodi.png", [email protected]"/Resources/Images/01077_1.png", Year="2001"},
            };

            _listBoxCars.ItemsSource = _carList;
        }
    }
執行程式,效果如下圖:


3. 控制元件的外衣ControlTemplate

  每每提到ControlTemplate我都會想到“披著羊皮的狼”這句話-----披上羊皮之後,雖然看上去像只羊,但其行為仍然是匹狼。狼的行為指的是它能吃別的動物、對著滿月嚎叫等事情,控制元件也有自己的行為,比如顯示資料、執行方法、激發事件等。控制元件的行為要靠程式設計邏輯來實現,所以也可以把控制元件的行為稱為控制元件的演算法內容。舉個例子,WPF中的CheckBox與其基類ToggleButton的功能幾乎完全一樣,但外觀差別上卻非常的大,這就是更換ControlTemplate的結果。經過更換ControlTemplate,我們不但可以製作披著CheckBox外衣的ToggleButton,還能製作披著溫度計外衣的ProgressBar控制元件。
注意:
實際專案中,ControlTemplate主要有兩大用武之地:
通過更換ControlTemplate來更換控制元件的外觀,使之具有更優的使用者體驗和外觀。
藉助ControlTemplate,程式設計師和設計師可以並行工作,程式設計師可以使用WPF標準控制元件進行程式設計,等設計師的工作完成之後,只需要把新的ControlTemplate應用的程式中即可。

    ItemsControl具有一個名為ItemsPanel的屬性,它的資料型別是ItemsPanelTemplate。ItemsPanelTemplate也是一種控制元件Template,它的作用是可以讓程式設計師可以控制ItemsControl的條目容器。

舉例而言,在我們的印象中ListBox中的條目都是至上而下排列的,如果客戶要求我們做一個水平排列的ListBox怎麼辦呢?WPF之前,我們只能重寫控制元件比較底層的方法和屬性,而現在我們只需要調整ListBox的ItemsPanel屬性。

<Window x:Class="WpfApplication11.wnd1132"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="wnd1132" Height="80" Width="300">
    <Grid>
        <ListBox>
            <!--條目容器-->
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"></StackPanel>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <!--條目元素-->
            <TextBlock Text="Allan"></TextBlock>
            <TextBlock Text="Allan2"></TextBlock>
            <TextBlock Text="Allan3"></TextBlock>
            <TextBlock Text="Allan4"></TextBlock>
        </ListBox>
    </Grid>
</Window>

條目就會包裝在一個水平排列的StackPanel中,從而橫向排列,如下圖所示:



相關推薦

WPF Template模版DataTemplateControlTemplate

    WPF系統不但支援傳統的Winfrom程式設計的使用者介面和使用者體驗設計,更支援使用專門的設計工具Blend進行專業設計,同時還推出了以模板為核心的新一代設計理念。 1. 模板的內涵   作為表現形式,每個控制元件都是為了實現某種使用者操作演算法和直觀顯示某種資料

Hadoop(初識大數據Hadoop轉載

hba 無效 理解 組織 鼠標 掌握 能夠 through 2.3 原文地址:http://www.cnblogs.com/zhangyinhua/p/7647334.html 閱讀目錄(Content) 一、引言(大數據時代) 1.1、從數據中得到信息 1.2、大數據

Unity序列化XML,JSON--------合成解析轉載

尊重原創,轉載請註明出處,謝謝! 最近在學熱更新,涉及到資源熱更,所以就瞭解了XML,JSON相關的東西。這方面網上資料還是比較多的,所以這裡主要是總結一下基本使用方法和一些應用的Demo。 1.先介紹一下 XML 和 JSON 是什麼東西吧? (1

java版資料結構演算法分析學習前言

一.資料結構和演算法概述?【框範圍】 基礎資料結構主要包括表【陣列+連結串列】、棧、佇列【散列表】、樹、圖、堆。高階資料結構包括伸展樹、紅黑樹、確定性跳躍表、AA樹、treap樹、k-d樹、配對堆。

JVM記憶體垃圾回收篇JVMJava體系結構

# JVM與Java體系結構 ## 前言 作為 Java 工程師的你曾被傷害過嗎?你是否也遇到過這些問題? 執行著的線上系統突然卡死,系統無法訪問,甚至直接 OOM(out of memory)! - 想解決線上 JVM GC 問題,但卻無從下手。 - 新專案上線,對各種 JVM 引數設定一臉茫然,直

JVM記憶體垃圾回收篇類載入子系統

# 類載入子系統 ## 概述 ![](https://img2020.cnblogs.com/blog/1542615/202007/1542615-20200713205844260-855669260.png) 完整圖如下: ![](https://img2020.cnblogs.com/blo

JVM記憶體垃圾回收篇執行時資料區概述及執行緒

# 執行時資料區概述及執行緒 ## 前言 本節主要講的是執行時資料區,也就是下圖這部分,它是在類載入完成後的階段 ![](https://img2020.cnblogs.com/blog/1542615/202007/1542615-20200713210432252-2095338296.png)

JVM記憶體垃圾回收篇物件例項化記憶體佈局訪問定位

# 物件例項化記憶體佈局與訪問定位 從各自具體的**記憶體分配**上來講 new 的物件放在**堆**中 物件所屬的型別資訊是放在**方法區**的 方法當中的區域性變數放在**棧空間** 這 new 的物件怎麼把三塊粘合到一起 就是這章的內容了 ## 物件例項化 ### 面試題 **美團:** - 物

6、自學——Linux的學習進度任務FHS

include 同名 med 可選 第三方 安裝 lin 三方 引導 FHS:文件層次標準 FHS:文件層次標準    / : 代表根目錄    /bin: 二進制文件,可執行程序,所有用戶都能用。   /sbin: 只有管理員執行的,二進制可執行程序。

排序檢索UVa10474Where is the Marble?

素數 指數 ive test posit muc not ria str Where is the

從一道面試題來認識java類加載時機過程

包含 布局 hello 印象 大致 周期 default () itl 說明:本文的內容是看了《深入理解Java虛擬機:JVM高級特性與最佳實踐》後為加印象和理解,便記錄了重要的內容。 1 開門見山 以前曾經看到過一個java的面試題,當時覺得此題很簡單,可是自己

JAVA Tomcat知識框架

規範 分享 輕量 war dad class 重要 開發 是否 一、Tomcat服務器(很熟悉) 1、Web開發概述 javaSE: javaEE:13種 javaME: JavaEE規範: 13種技術的總稱。Servlet/Jsp JDBC JNDI JTA

c#中常用集合類和集合接口集合類系列

arr 關聯 special rect 替代 不能 一個數 lock resize 常用集合接口系列:http://www.cnblogs.com/fengxiaojiu/p/7997704.html 常用集合類系列:http://www.cnblogs.com/fengx

kotlin web開發教程從零搭建kotlinspring boot開發環境

1.8 jre cond utf8 erro 2.0 .com 就會 一個tomcat IDEA中文輸入法的智能提示框不會跟隨光標的問題我用的開發工具是IDEA這個版本的IDEA有一個問題;就是中文輸入法的智能提示框不會跟隨光標解決這個問題的辦法很簡單,只有在安裝目錄下把J

Linux學習路--日誌管理17---20180113

ocs title 軟件 config mil 集中 auto 表示 rap 一、日誌介紹日誌: 歷史事件:時間,地點,人物,事件 日誌級別:事件的關鍵性程度,Loglevel系統日誌服務:sysklogd :CentOS 5之前版本 syslog

嵌入式Linux截圖工具gsnap移植分析

ram creat 嵌入式linux mbed 生活 rip 改變 因此 sig 轉自:http://blog.csdn.net/lu_embedded/article/details/53934184 版權聲明:開心源自分享,快樂源於生活 —&mdash

SpringCloud學習sleuth&zipkin

bus dep char str gradle 問題 -m onclick runt   這篇文章我們針對上篇鏈路跟蹤的遺留問題進行改造升級 一、將追蹤數據存放到MySQL數據庫中   默認情況下zipkin將收集到的數據存放在內存中(In-Memeroy),但是不可避

LOJ6387 [THUPC2018] 綠綠串串 manacher

pan set tin return sca size sizeof 分析 AR 題目分析: 比較簡單,先跑一邊manacher,然後對於回文部分可以碰到末尾的一定滿足條件,否則向後轉移。 代碼: 1 #include<bits/stdc++.h> 2 u

對博弈的深度理解為什麼異或

曉神對博弈的理解已經超出了我的理解了,超強! 昨晚上一道博弈題讓我又理解了一下博弈,趕緊掏出我的小本子; 1 尼姆博弈我們都是知道的如果是每一個狀態的sg值異或完後如果是非零先手必有勝的策略否則沒有, 這裡再說一下是為什麼

[Flink基本概念部署]--Flink 程式設計模型

一、Flink基本程式設計模型 圖1   1、Stateful Stream Processing 它位於最底層, 是core API 的底層實現;推薦學習時使用,生產中以穩定為主,不建議使用。 processFunction:開