使用Blend設計WPF ItemsControl

by Vivid 3. 五月 2011 10:23

Items Control是一個由許多子項目所成的集合組成的控制項,例如ListBox、ComboBox、Menus便是其中的一種控制項,因此Item Controls通常被稱為list-based的控制項。Items Control並沒有限制要顯示哪些內容,您可以利用多種方式來客製化它的外觀,例如在ListBox控制項中,可以顯示一堆CheckBox控制項,而不是受限只能顯示ListBoxItem項目。

說到設計微軟.NET類型的應用程式,多半會使用Visual Studio 2010工具來進行開發。但是WPF應用程式需要更簡易的方式來操作、產生Xaml或是製作動畫…等等,這就非Visual Studio 2010工具的強項,遇到需要設計WPF類型的應用程式,Microsoft Expression Blend 4是另一種選擇,因此本文將使用Microsoft Expression Blend 4來設計WPF應用程式,介紹如何利用工具來為Items Control設計展示資料的樣式(Style)、樣版(Template)。

我們以一個使用ListBox控制項的範例當做說明的範本,您可以使用Microsoft Expression Blend 4建立一個WPF Application專案,從「File」->「New Project」,從對話方塊中選取「WPF Application」,然後輸入專案的名稱。

ListBox是最簡單的Item Control。進入到Microsoft Expression Blend 4設計畫面後,使用滑鼠雙擊工具箱的ListBox控制項,它就會自動新增到工具中間的設計畫面。

ItemsPanelTemplate樣版

ItemsControl擁有一個ItemsPanel屬性,可以讓你選用一種Panel類型的控制項來顯示內容。接下來我們要加入ItemsPanelTemplate樣版。從Microsoft Expression Blend 4視覺化的設計畫面選取ListBox控制項,點選滑鼠右鍵,然後選取突顯示對話方塊中的「Edit Additional Templates」->「Edit Layout of Items [ItemsPanel]」->「Edit a Copy」,參考圖1所示。

clip_image002

圖 1:Edit Layout of Items [ItemsPanel]

在「Create ItemsPanelTemplate Resource」對話盒中,設定一個Name(Key),例如本範例中輸入「MyItemsPanelTemplate」,其它保留預設值,然後按下「OK」按鈕。

完成這的動作後,Microsoft Expression Blend 4會自動產生如下Xaml標籤,在Window.Resources中會自動建立ItemsPanelTemplate樣版,設定key為「MyItemsPanelTemplate」,而ListBox的ItemsPanel屬性則利用動態資源方式繫結到MyItemsPanelTemplate。

<Window

xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"

x:Class = "WpfApplication2.MainWindow" x:Name = "Window" Title="MainWindow" Width="640" Height="480">

<Window.Resources>

<ItemsPanelTemplate x:Key = "MyItemsPanelTemplate" >

<VirtualizingStackPanel IsItemsHost = "True" />

</ItemsPanelTemplate>

</Window.Resources>

<Grid x:Name = "LayoutRoot">

<ListBox HorizontalAlignment = "Left" Height = "100" VerticalAlignment = "Top" Width = "100"

ItemsPanel = "{DynamicResource MyItemsPanelTemplate}" />

</Grid>

</Window>

檢視其中的Xaml標籤,ItemsPanelTemplate內含一個VirtualizingStackPanel控制項,其IsItemsHost屬性設定為True,表示VirtualizingStackPanel控制項被視為一個容器,用來置放控制項包含的項目。VirtualizingStackPanel控制項類似StackPanel控制項,適用在Items Control中的子項目很多的情況下,它只會為目前視窗中看的到的子項目建立Visual Tree,並適當地進行最佳化處理。

值得一提的是,在WPF 4版中,VirtualizingStackPanel控制項支援一個VirtualizingStackPanel.VirtualizationMode附加屬性,你可以在ListBox控制項中將其設定為Recycling常數值,如此VirtualizingStackPanel控制項就會重複使用用來顯示畫面上子項目的容器控制項,而不會為每個項目重新建立。語法如下:

<ListBox VirtualizingStackPanel.VirtualizationMode = "Recycling" …/>

當然,你可以把VirtualizingStackPanel控制項置換成其它Panel類型的控制項,如WrapPanel控制項。

除了使用IsItemsHost屬性來客製化樣版之外,還有一種作法,定義ItemsPanelTemplate樣版,在樣版之中加入置放可包含項目的容器控制項。舉例來說,在我們的範例中不想使用VirtualizingStackPanel控制項,因此您可以直接將其刪除,從「Objects and Timeline」視窗中,選取VirtualizingStackPanel項目,按滑鼠右鍵,從突顯式選單方塊中選取「Delete」,參考圖2所示。

clip_image004

圖 2:刪除VirtualizingStackPanel控制項

因為希望ListBox項目能夠有自動換行效果,在ItemsPanelTemplate樣版中改用WrapPanel控制項。接下來將WrapPanel控制項加到ItemsPanelTemplate樣版,選取「Objects and Timeline」視窗中的ItemsPanelTemplate項目,雙擊工具箱WrapPanel控制項,就會自動將其新增到設計樣版,參考圖3所示。

clip_image006

圖 3:設計ItemsPanelTemplate樣版

使用屬性視窗設定Wrap Panel的Orientation屬性為「Vertical」。到目前為止您的Xaml大約如下所示。

<Window xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" x:Class = "WpfApplication2.MainWindow"

x:Name = "Window" Title = "MainWindow" Width = "640" Height = "480" >

<Window.Resources>

<ItemsPanelTemplate x:Key = "MyItemsPanelTemplate" >

<WrapPanel Orientation = "Vertical" />

</ItemsPanelTemplate>

</Window.Resources>

<Grid x:Name = "LayoutRoot" >

<ListBox HorizontalAlignment = "Left" Height = "100" VerticalAlignment = "Top" Width = "100"

ItemsPanel = "{DynamicResource MyItemsPanelTemplate}" />

</Grid>

</Window>

這樣ListBox控制項就可以使用ItemsPanel屬性來參考到新建立的MyItemsPanelTemplate樣版。

設定ListBox 控制項的樣式(Style)

Style可以用來設定FrameworkElement的共用屬性。我們來看一下如何利用Microsoft Expression Blend 4來設定ListBox控制項的樣式。選取中間設計畫面上方的ListBox控制項右方的下拉式清單->「Edit Template」->「Edit a Copy」,參考圖4所示。

clip_image008

圖 4:新增Style

此時就會自動跳出一個「Create Style Resource」對話盒,設定其Name(key)為「MyListBoxStyle」,其它保留預設值。預設Items Control會使用ItemsPresenter來顯示所有的項目。

ItemsPresenter項目主要是用來做定位,你可以將之視為一個定位器(Placeholder),此項目出現的地方,就是ListBox控制項中每個項目要顯示的內容。當你不想使用特定類型的Panel控制項當做Items Control的樣版時,而想使用任意類型的Panel,就可以在ControlTemplate中搭配使用ItemsPresenter項目。

使用ItemsPresenter項目取代ScrollViewer控制項,在「Objects and Timeline」視窗中,拖曳ScrollViewer控制項到Bd項目上方然後放開,參考圖5所示。

clip_image010

圖 5:使用ItemsPresenter項目取代ScrollViewer控制項

此時產生的XAML如下,Microsoft Expression Blend 4會殘留一些ScrollViewer控制項的設定,如不需要可逕行刪除:

<Window xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:Microsoft_Windows_Themes = "clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" x:Class = "WpfApplication2.MainWindow"

x:Name = "Window" Title = "MainWindow" Width = "640" Height = "480" >

<Window.Resources>

<ItemsPanelTemplate x:Key = "MyItemsPanelTemplate" >

<WrapPanel Orientation = "Vertical" />

</ItemsPanelTemplate>

<Style x:Key = "MyListBoxStyle" TargetType = "{x:Type ListBox}" >

<Setter Property = "Background" Value = "{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />

<Setter Property = "Foreground" Value = "{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />

<Setter Property = "BorderBrush"

Value = "{x:Static Microsoft_Windows_Themes:ClassicBorderDecorator.ClassicBorderBrush}" />

<Setter Property = "BorderThickness" Value="2" />

<Setter Property = "ScrollViewer.HorizontalScrollBarVisibility" Value = "Auto" />

<Setter Property = "ScrollViewer.VerticalScrollBarVisibility" Value = "Auto" />

<Setter Property = "ScrollViewer.CanContentScroll" Value = "true" />

<Setter Property = "ScrollViewer.PanningMode" Value = "Both" />

<Setter Property = "Stylus.IsFlicksEnabled" Value = "False" />

<Setter Property = "VerticalContentAlignment" Value = "Center" />

<Setter Property = "Template" >

<Setter.Value>

<ControlTemplate TargetType = "{x:Type ListBox}" >

<Microsoft_Windows_Themes:ClassicBorderDecorator x:Name = "Bd"

BorderBrush = "{TemplateBinding BorderBrush}" BorderThickness = "{TemplateBinding BorderThickness}"

BorderStyle = "Sunken" Background = "{TemplateBinding Background}" SnapsToDevicePixels = "true" >

<ItemsPresenter SnapsToDevicePixels = "{TemplateBinding SnapsToDevicePixels}"

d:LayoutOverrides = "Width, Height" />

</Microsoft_Windows_Themes:ClassicBorderDecorator>

<ControlTemplate.Triggers>

<Trigger Property = "IsEnabled" Value = "false">

<Setter Property = "Background" TargetName = "Bd"

Value = "{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>

</Trigger>

<Trigger Property = "IsGrouping" Value = "true">

<Setter Property = "ScrollViewer.CanContentScroll" Value = "false" />

</Trigger>

</ControlTemplate.Triggers>

</ControlTemplate>

</Setter.Value>

</Setter>

</Style>

</Window.Resources>

<Grid x:Name = "LayoutRoot" >

<ListBox HorizontalAlignment = "Left" Height = "100" VerticalAlignment = "Top" Width = "100"

ItemsPanel = "{DynamicResource MyItemsPanelTemplate}" Style = "{DynamicResource MyListBoxStyle}" />

</Grid>

</Window>

注意到< ControlTemplate >中使用到了TemplateBinding繫結來控制一些屬性,像是Background。將來設定ListBox控制項的Background屬性時,就會自動地套用到ControlTemplate中項目的相同的屬性,這樣ListBox控制項中項目的背景顏色才會和ListBox控制項的背景顏色一致。

回到MainWindow設計畫面,為ListBox控制項加上一些ListBoxItem。點選畫面上的「ListBox」,點選屬性視窗Items (Collection)後方的按鈕,進入到Collection Editor對話盒,參考圖6所示。

clip_image012

圖 6:新增項目

在Collection Editor對話盒,點選下方的「Add another item」->「ListBoxItem」新增Item,然後適當地設定每個ListBoxItem的Content屬性,參考圖7所示。

clip_image014

圖 7:為ListBox控制項新增ListBoxItem

Microsoft Expression Blend 4會自動產生ListBoxItem項目,並設定Style屬性套用到MyListBoxStyle。

<ListBox HorizontalAlignment = "Left" Height = "100" VerticalAlignment = "Top" Width = "100"

ItemsPanel = "{DynamicResource MyItemsPanelTemplate}" Style = "{DynamicResource MyListBoxStyle}" >

<ListBoxItem Content = "Mary"/>

<ListBoxItem Content = "Candy"/>

<ListBoxItem Content = "Judy"/>

</ListBox>

回到設計畫面,當調整畫面上ListBox控制項的高度不夠其中子項目時,就會自動換行,參考圖8所示。

clip_image016

圖 8:ListBox套用Style

設定ListBox DataTemplate

在有資料繫結的情況下,使用DataTemplate能更精確地掌控Items Control想要顯示的內容。在Microsoft Expression Blend 4中,若要為ListBox控制項新增資料樣版,從MainWindow設計畫面上方,點選畫面上的「ListBox」,點選「Edit Additional Templates」->「Edit Generated Items (ItemTemplate)」->「Create a Copy」,參考圖9所示。

clip_image018

圖 9:新增資料樣版(DataTemplate)

在「Create DataTemplate Resource」對話盒中設定Name(key)為「MyDataTemplate」。刪掉預設的Grid項目,從「Objects and Timeline」視窗,點選DataTemplate下方的Grid項目,然後按鍵盤Delete鍵。接著在DataTemplate下方加入一個TextBlock控制項,參考圖10所示。

clip_image020

圖 10:設計資料樣板

切換Microsoft Expression Blend 4到Xaml編輯畫面,直接修改Xaml,將DataTemplate中TextBlock項目的Text屬性設定為{Binding}:

<DataTemplate x:Key = "MyDataTemplate" >

<TextBlock TextWrapping = "Wrap" Text = "{Binding}" />

</DataTemplate>

將TextBlock放入一個StackPael控制項。從「Objects and Timeline」視窗選取TextBlock,按滑鼠右鍵,選取「Group Into」->「StackPanel」,參考圖11所示。

clip_image022

圖 11:將TextBlock放入一個StackPael控制項

利用屬性視窗將StackPanel的Oriention屬性設定為「Horizontal」。

下一個步驟是新增Image控制項到資料樣版。在DataTemplate的StackPanel下加一個Image控制項,目前「Objects and Timeline」視窗MyDataTemplate看起來如圖12所示。

clip_image024

圖 12:新增Image控制項到資料樣版

利用屬性視窗設定Image控制項的Source屬性為info.png檔。到這個步驟,Visual Studio會自動產生以下Xaml標籤。(Info.png檔案要事先加入到專案,從Microsoft Expression Blend 4的「Projects」視窗,選取WPF專案,按滑鼠右鍵,選「Add Existing Item」)。

<DataTemplate x:Key = "MyDataTemplate" >

<StackPanel Orientation = "Horizontal" Width = "48" >

<Image Height = "38" Source = "info.png" HorizontalAlignment = "Left" Width = "20"/>

<TextBlock TextWrapping = "Wrap" Text = "{Binding}" d:LayoutOverrides = "Width"/>

</StackPanel>

</DataTemplate>

回到MainWindow視窗,移除ListBox控制項中的ListBoxItem。最快的方式就是直接將Xaml中的所有<ListBoxItem../>項目刪除。

設定ListBox DataTemplate—設計資料類別

接下來我們要設計資料類別以便於進行資料繫結。在「Projects」視窗專案名字上方,按滑鼠右鍵,從選單中選取「Add New Item」,然後選取Class,新增一個類別檔案,設定Name為「MyDataClass」。

接著在MyDataClass類別中,加入以下程式碼,宣告一個類別階層的變數data,型別為List<string>,在MyDataClass建構函式中新增三個字串。然後加入一個ListOfString屬性,回傳data。

public class MyDataClass

{

List<string> data = new List<string>();

public MyDataClass()

{

data.Add("Mary");

data.Add("Candy");

data.Add("Judy");

}

public List<string> ListOfString

{

get {return data;}

}

}

為了確保程式沒有寫錯,在此階段先進行編譯,選取Microsoft Expression Blend 4的「Project」->「Build Project」。

回到MainWindow設計畫面,點選ListBox控制項,利用屬性視窗設定DataContext屬性。從DataContext屬性後方,點選「New」,在「Select Object」對話盒中選取MyDataClass。

設定ListBox控制項的ItemsSource屬性,點選ItemsSource屬性後方的「Advanced Options」->「Data Binding」,參考圖13所示。

clip_image026

圖 13:設定ListBox控制項的ItemsSource屬性

設定Fields為MyDataClass的ListOfString屬性,參考圖14所示。

clip_image028

圖 14:設定Fields

目前Xaml看起來如下:

<ListBox HorizontalAlignment = "Left" Height = "128" VerticalAlignment = "Top" Width = "136"

ItemsPanel = "{DynamicResource MyItemsPanelTemplate}" Style = "{DynamicResource MyListBoxStyle}" ItemTemplate = "{DynamicResource MyDataTemplate}" ItemsSource = "{Binding ListOfString}">

<ListBox.DataContext>

<local:MyDataClass />

</ListBox.DataContext>

</ListBox>

回到MainWindow,在設計畫面中ListBox套用了資料樣版,每個項目前方都會有一個info.png圖型,參考圖15所示。

clip_image030

圖 15:套用資料樣版

總結

Microsoft Expression Blend 4能夠幫助設計WPF與Silverlight所需的Xaml標籤。WPF常使用三種不同的Presenter來顯示內容。在控制項有Content屬性,繼承自ContentControl時,可以使用ContentPresenter來顯示內容,如Label、Button控制項。只要控制項繼承自ItemsControl,且有Items屬性時,您可以使用ItemsPresenter項目來顯示內容。ScrollContentPresenter繼承自ContentPresenter,實作了IScrollInfo介面,但只能夠搭配ScrollViewer控制項使用。

Tags:

Expression Blend | WPF | 許薰尹Vivid Hsu | .NET Magazine國際中文電子雜誌

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List