1. 程式人生 > >WPF 模板

WPF 模板

url for mapi grid app 什麽 oca namespace 分別是

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", ImagePath=@"/Resources/Images/Aodi.jpg", Automarker=@"/Resources/Images/01077_1.png", Year="1990"},  
            new Car(){Name = "Aodi2", ImagePath=@"/Resources/Images/Aodi.png", Automarker=@"/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中,從而橫向排列,如下圖所示:

技術分享圖片

轉自http://www.cnblogs.com/lizhenlin/p/5906729.html

WPF 模板