0.前言
此文主要介紹WPF的基礎(chǔ)知識,文章會直接摘抄一些優(yōu)秀文章的表達(dá)以及示例用于說明,如果侵犯了作者權(quán)利,請聯(lián)系我速刪。編寫文章的目的在于記錄與分享,方便后續(xù)重溫與掌握。文章中可能會存在一些小問題,還望各位看官不吝指出。
1.XAML
1.1WPF簡介
WPF(Windows Presentation Foundation) 是創(chuàng)建桌面客戶端應(yīng)用程序的UI框架。WPF開發(fā)平臺支持廣泛的應(yīng)用開發(fā)功能,包括應(yīng)用模型、資源、控件、圖形、布局、數(shù)據(jù)綁定、文檔和安全性。WPF是.Net的一部分,WPF 使用 XAML(Extensible Application Markup Language)為應(yīng)用編程提供聲明性模型。
1.2XAML
1.定義
可擴(kuò)展應(yīng)用程序標(biāo)記語言 (XAML) 是一種基于 XML 的聲明性語言,可用于創(chuàng)建應(yīng)用程序UI,其廣泛用于以下類型的應(yīng)用程序:
- Windows Presentation Fundation(WPF)應(yīng)用
- 通用Windows平臺(UWP)應(yīng)用
- Xamarin.Forms應(yīng)用
2.優(yōu)勢
將界面設(shè)計與邏輯編碼分離,例如,設(shè)計人員可以設(shè)計一個UI,然后將 XAML 文件交給開發(fā)人員以添加邏輯代碼。即使設(shè)計人員和開發(fā)人員是同一個人(通常如此),程序員也可以將視覺內(nèi)容保存在 XAML 文件(.xaml)中,而將邏輯代碼保存在代碼隱藏文件(.cs)中。
3.例子
下面的例子中涉及WPF中的一些概念,如布局控件、內(nèi)容控件、x:前綴、數(shù)據(jù)綁定等,這些概念后面都會介紹到,例子用于對 XAML 有個初步的認(rèn)識。
<Window x:Class="WPFLearn.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Services"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="500" Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="234*"/>
<RowDefinition Height="134*"/>
<RowDefinition Height="67*"/>
</Grid.RowDefinitions>
<Canvas Grid.Row="0" Margin="0,0,0,67" Grid.RowSpan="3">
<Ellipse x:Name="EllipseRed" Fill="Red" Width="100" Height="60" Canvas.Left="56" Canvas.Top="98" local:TurnoverManager.Angle="{Binding ElementName=SliderAngle,Path=Value}"/>
<Rectangle x:Name="RectangleBlue" Fill="Blue" Width="80" Height="80" Canvas.Left="288" Canvas.Top="171" local:TurnoverManager.Angle="45"/>
<Button x:Name="ButtonWelcome" Content="歡迎光臨" Canvas.Left="265" Canvas.Top="48" FontSize="20" local:TurnoverManager.Angle="60"/>
</Canvas>
<WrapPanel Grid.Row="2">
<Label Content="角度大小"/>
<Slider x:Name="SliderAngle" Minimum="0" Maximum="240" Width="300"/>
</WrapPanel>
</Grid>
</Window>
1.2語法
XAML 語法這一部分基本內(nèi)容都是摘抄微軟官方的WPF中的 XAML 概述,只不過進(jìn)行了小部分的詞語修改以及增加 Demo,降低理解難度。
1.對象元素
對象元素通常聲明類型的實例,該類型在將 XAML 用作語言的技術(shù)所引用的程序集中定義。指定對象元素標(biāo)記時,會創(chuàng)建一條指令,指示 XAML 解析器創(chuàng)建基礎(chǔ)類型的新實例。每個實例都是在分析和加載 XAML 時通過調(diào)用基礎(chǔ)類型的無參數(shù)構(gòu)造函數(shù)來創(chuàng)建。
<Grid>
<Button Content="Click Me!"/>
</Grid>
注解: Grid、Button都是對象元素。
2.特性語法(屬性)
(1)對象的屬性通??杀硎緸閷ο笤氐奶匦浴?br> (2)對象的特性語法為:property=“value”。
(3)特性的值始終指定為包含在引號中的字符串。
<Button Background="Blue" Foreground="Red" Content="Click Me!"/>
注解: Background=“Blue”、Foreground=“Red”、Content=“Click Me!” 都是屬性的特性語法。
3.屬性元素語法
對于對象元素的某些屬性,無法使用特性語法,因為無法在特性語法的引號和字符串限制內(nèi)充分地為屬性值提供所必需的對象或信息。 對于這些情況,可以使用另一個語法,即屬性元素語法。
<!--使用屬性語法代替特性語法-->
<Button>
<Button.Background>
<SolidColorBrush Color="Blue"/>
</Button.Background>
<Button.Foreground>
<SolidColorBrush Color="Red"/>
</Button.Foreground>
<Button.Content>
Click
</Button.Content>
</Button>
<!--使用屬性語法創(chuàng)建漸變色-->
<Grid >
<Rectangle Width="200" Height="200">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
注解:
1.第一個 Button 使用了屬性語法來賦值 Background、Foreground、Content ,最終效果與前一點的示例一樣。
2.第二個 Button 使用了屬性語法來創(chuàng)建漸變色,由于漸變色對象無法在雙引號中被表達(dá),所以只能使用這種方式給屬性賦值。
3.如果可以使用特性語法給屬性賦值的話,就選擇特性語法,這樣會使內(nèi)容簡潔、編寫高效。
4.集合語法
XAML 語言包含一些優(yōu)化,可以生成更易于閱讀的標(biāo)記。其中一項優(yōu)化是:如果某個特定屬性采用集合類型,則在標(biāo)記中聲明為該屬性值內(nèi)的子元素的項目將成為集合的一部分。在這種情況下,子對象元素的集合是設(shè)置為集合屬性的值。
<!--顯式聲明集合屬性-->
<Grid >
<Rectangle Width="200" Height="200">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStopCollection>
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</GradientStopCollection>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
<!--沒有聲明集合屬性,效果相同-->
<Grid >
<Rectangle Width="200" Height="200">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
注解: 第二個 Rectangle 設(shè)置漸變色時,雖然省略了集合元素 GradientStopCollection ,但 XAML 處理器依舊可以處理得到相同的結(jié)果。
5.內(nèi)容屬性
XAML 指定了一個語言功能,通過該功能,類可以指定它的有且僅有一個的屬性為 XAML 內(nèi)容屬性。該對象元素的子元素用于設(shè)置該內(nèi)容屬性的值。換言之,僅對內(nèi)容屬性而言,可以在 XAML 標(biāo)記中設(shè)置該屬性時省略屬性元素,并在標(biāo)記中生成更直觀的父級/子級形式。
<!--顯示聲明內(nèi)容屬性-->
<Border>
<Border.Child>
<TextBox Width="300"/>
</Border.Child>
</Border>
<!--沒有聲明內(nèi)容屬性,效果相同-->
<Border>
<TextBox Width="300"/>
</Border>
注解: 本質(zhì)同集合語法類似,都是 XAML 處理器進(jìn)行了一些優(yōu)化,兼容支持了多種寫法,此處是省略表示內(nèi)容屬性的 Border.Child 元素。
6.文本內(nèi)容
有少量 XAML 元素可直接將文本作為其內(nèi)容來處理。若要實現(xiàn)此功能,必須滿足以下條件之一:
- 類必須聲明一個內(nèi)容屬性,并且該內(nèi)容屬性必須是可賦值給字符串的類型(該類型可以是Object)。
- 類型必須聲明一個類型轉(zhuǎn)換器,該類型轉(zhuǎn)換器將文本內(nèi)容用作初始化文本。
- 類型必須為已知的XAML語言基元。
<Button>Hello</Button>
<Brush>Blue</Brush>
注解: 本質(zhì)都是 XMAL 處理器的優(yōu)化處理。
7.特性語法(事件)
特性語法還可用于事件成員,而非屬性成員。 在這種情況下,特性的名稱為事件的名稱。在 XAML 事件的 WPF 實現(xiàn)中,特性的值是實現(xiàn)該事件的委托的處理程序的名稱。
<Button Click="Button_Click" >
Click Me!
</Button>
注解: 上述的 XAML 文件關(guān)聯(lián)的 CS 文件中,定義了名稱為 Button_Click 的函數(shù)。
8.大小寫和空白
一般而言,XAML 區(qū)分大小寫。XAML 中的值并不總是區(qū)分大小寫:值是否區(qū)分大小寫將取決于與采用該值的屬性關(guān)聯(lián)的類型轉(zhuǎn)換器行為,或取決于屬性值類型。例如,采用 Boolean 類型的屬性可以采用 true 或 True 作為等效值,但只是因為將字符串轉(zhuǎn)換為 Boolean 的本機(jī) WPF XAML 分析程序類型轉(zhuǎn)換已經(jīng)允許將這些值作為等效值。
WPF XAML 處理器和序列化程序?qū)⒑雎曰騽h除所有無意義的空白,并標(biāo)準(zhǔn)化任何有意義的空白,即 XAML 將空格、換行符和制表符轉(zhuǎn)化為空格,如果它們在一個字符串的任一端連續(xù)出現(xiàn),則保留一個空格。
9.標(biāo)記擴(kuò)展
標(biāo)記擴(kuò)展是一個 XAML 語言概念。在提供特性語法的值時,用大括號({ 和 })表示標(biāo)記擴(kuò)展用法。 此用法指示 XAML 處理器不要像通常那樣將特性值視為文本字符串或者可轉(zhuǎn)換為字符串的值。
WPF 應(yīng)用編程中最常用的標(biāo)記擴(kuò)展是 Binding(用于數(shù)據(jù)綁定表達(dá)式)以及資源引用 StaticResource 和 DynamicResource 。通過使用標(biāo)記擴(kuò)展,即使屬性通常不支持特性語法,也可以使用特性語法為屬性提供值。標(biāo)記擴(kuò)展經(jīng)常使用中間表達(dá)式類型實現(xiàn)一些功能,例如,引用僅在運行時才存在的值。
<Window x:Class="index.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="100" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="BorderBrush" Value="Blue"/>
<Setter Property="BorderThickness" Value="5" />
</Style>
</Window.Resources>
<Border Style="{StaticResource PageBackground}">
<StackPanel>
<TextBlock Text="Hello" />
</StackPanel>
</Border>
</Window>
注解: 以上標(biāo)記使用特性語法設(shè)置 Style 屬性的值。Style 屬性采用 Style 類的實例,該類在默認(rèn)情況下無法由特性語法字符串進(jìn)行實例化。但在本例中,特性引用了特定的標(biāo)記擴(kuò)展 StaticResource 。XAML 處理器處理該標(biāo)記擴(kuò)展時,將返回在資源字典中實例化的某個樣式的引用。
10.根元素和命名空間
一個 XAML 文件只能有一個根元素,以便同時作為格式正確的 XML 文件和有效的 XAML 文件。對于典型 WPF 方案,可使用在 WPF 應(yīng)用模型中具有突出意義的根元素(例如,頁面的 Window 或 Page 、外部字典的 ResourceDictionary 或應(yīng)用定義的 Application )。
根元素還包含特性 xmlns 和 xmlns:x 。這些特性向 XAML 處理器指示哪些 XAML 命名空間包含標(biāo)記將其作為元素引用的后備類型的類型定義。 xmlns 特性明確指示默認(rèn)的 XAML 命名空間。在默認(rèn)的 XAML 命名空間中,可以不使用前綴指定標(biāo)記中的對象元素。對于大多數(shù) WPF 應(yīng)用程序方案以及 SDK 的 WPF 部分中給出的幾乎所有示例,默認(rèn)的 XAML 命名空間均映射到 WPF 命名空間http://schemas.microsoft.com/winfx/2006/xaml/presentation。xmlns:x 特性指示另一個 XAML 命名空間,該命名空間映射 XAML 語言命名空間http://schemas.microsoft.com/winfx/2006/xaml。
只有在每個 XAML 文件的根元素上, xmlns 特性才是絕對必需的。 xmlns 定義將應(yīng)用于根元素的所有后代元素。 xmlns 屬性也允許位于根下的其他元素上,并將應(yīng)用于定義元素的任何后代元素。 但是,頻繁定義或重新定義 XAML 命名空間會導(dǎo)致難以閱讀 XAML 標(biāo)記樣式。
<Page x:Class="index.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
</Page>
11.x:前綴
常用的 x: 前綴如下:
前綴 | 作用 |
---|---|
x:Key | 為(或其他框架中的類似字典概念)每個資源設(shè)置唯一的鍵。 |
x:Class | 向為XAML 頁提供代碼隱藏的類指定 CLR 命名空間和類名。必須具有這樣一個類才能支持每個 WPF 編程模型的代碼隱藏。 |
x:Name | 處理對象元素后,為運行時代碼中存在的實例指定運行時對象名稱。通常,經(jīng)常為 x:Name 使用 WPF 定義的等效屬性。此類屬性特定映射到 CLR 后備屬性,因此更便于進(jìn)行應(yīng)用編程,在應(yīng)用編程中,經(jīng)常使用運行時代碼從初始化的 XAML 中查找命名元素。 最常見的此類屬性是 FrameworkElement.Name 。在特定類型中不支持等效的 WPF 框架級屬性時,仍然可以使 x:Name 。 |
x:Type | 根據(jù)類型名稱構(gòu)造引用。用于指定采用 Type(例如 Style.TargetType)的特性,但屬性經(jīng)常具有本機(jī)的字符串到 Type 的轉(zhuǎn)換功能,因此使用 Type 標(biāo)記擴(kuò)展用法是可選的。 |
x:Null | 在XAML中指定null值。 |
注解:
1.指定 Name 的兩種方式:Name = “buttonName” 和 x:Name = “buttonName” 。
2.指定 Type 的兩種方式:TargetType = “{x:Type Button}” 和 TargetType = “Button” 。
3.x:Null 用于顯示指定控件樣式為空,來避免指定了類型的樣式的全局應(yīng)用。
12.自定義前綴和自定義類型
對于自身的自定義程序集或 PresentationCore、PresentationFramework 和 WindowsBase 的 WPF 核心以外的程序集,可以將該程序集指定為自定義映射的一部分。只要該類型能夠正確地實現(xiàn)以支持正在嘗試的 XAML 用法,就可以在 XAML 中引用該程序集中的類型。
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary"
>
<StackPanel Name="LayoutRoot">
<custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/>
</StackPanel>
</Page>
13.附加屬性和附加事件
XAML 指定了一個語言功能,該功能允許對任何元素指定某些屬性或事件,即使要設(shè)置屬性或事件的元素的類型定義中不存在該屬性或事件。該功能的屬性版本稱為附加屬性,事件版本稱為附加事件。從概念上講,可以將附加屬性和附加事件視為可以在任何 XAML 元素/對象實例上設(shè)置的全局成員。
附加屬性的最常見方案是使子元素向其父元素報告屬性值。
<DockPanel Button.Click="DockPanel_Click">
<Button DockPanel.Dock="Left" Width="100" Height="20">
I am on the left
</Button>
<Button DockPanel.Dock="Right" Width="100" Height="20">
I am on the right
</Button>
</DockPanel>
注解:
1.上述中的 DockPanel 元素在自身中給 Button.Click 屬性事件賦值,而這個屬性是不屬于 DockPanel 元素的,這便是附加事件。在父元素中處理子元素的事件也體現(xiàn)了 WPF 的另一個特性,即路由事件。路由事件就是在 WP F中,事件會按照元素樹向上或向下傳遞,直到被設(shè)置了已處理的標(biāo)識符。
2.上述中的 Button 元素在自身中給 DockPanel.Dock 屬性賦值,而這個屬性是不屬于 Button 元素的,這便是附加屬性。
2.控件
2.1控件分類
WPF 中所有控件都繼承自 Control ,根據(jù)用途不同分為四種類型:布局控件(Panel Controls)、內(nèi)容控件(Content Controls)、條目控件(Items Controls)、特殊控件(Special Controls)。
2.1.1布局控件
WPF 的布局控件都繼承于 System.Windows.Controls.Panel ,常用的布局控件有:Canvas、StackPanel、WrapPanel、DockPanel、Grid、ScrollViewer。
1.Canvas
Canvas 是一個類似于坐標(biāo)系的面板,所有的元素通過設(shè)置坐標(biāo)來決定其在坐標(biāo)系中的位置.。具體表現(xiàn)為使用 Left、Top、Right、 Bottom 附加屬性在 Canvas 中定位控件。
Canvas 默認(rèn)不會自動裁剪超過自身范圍的內(nèi)容,即溢出的內(nèi)容會顯示在 Canvas 外面,可以設(shè)置 ClipToBounds 屬性來裁剪多出的內(nèi)容。
<Canvas Margin="10,10,10,10" Background="White" >
<Rectangle Name="rect" Canvas.Left="300" Canvas.Top="180" Fill="Black" Stroke="Red" Width="200" Height="200"/>
<Ellipse Name="el" Canvas.Left="160" Canvas.Top="150" Fill="Azure" Stroke="Green" Width="180" Height="180"/>
</Canvas>
2.StackPanel
StackPanel 將控件按照行或列來順序排列,但不會換行。通過設(shè)置面板的 Orientation 屬性控制兩種排列方式:橫排(Horizontal)和豎排(Vertical),默認(rèn)為豎排(Vertical)。
<StackPanel Margin="10,10,10,10" Background="Azure">
<Label>A Button Stack</Label>
<Button Content="Button 1"></Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button Content="Button 4"></Button>
</StackPanel>
3.WrapPanel
WrapPanel 布局面板將各個控件按照一定方向羅列,當(dāng)長度或高度不夠時自動調(diào)整進(jìn)行換行換列。
- Orientation=“Horizontal” 時各控件從左至右羅列,當(dāng)面板長度不夠時,子控件就會自動換行,繼續(xù)按照從左至右的順序排列。
- Orientation=“Vertical” 時各控件從上至下羅列,當(dāng)面板高度不夠時,子控件就會自動換列,繼續(xù)按照從上至下的順序排列。
<WrapPanel Margin="10" Background="Azure">
<Button VerticalAlignment="Top" Margin="5">
Top Button
</Button>
<Button MinHeight="50">
Tall Button
</Button>
<Button VerticalAlignment="Bottom">
Bottom Button
</Button>
<Button>
Stretch Button
</Button>
<Button VerticalAlignment="Center">
Center Button
</Button>
<Button>
Next Button
</Button>
</WrapPanel>
4.DockPanel
DockPanel 支持讓元素簡單地停靠在整個面板的某一條邊上,然后拉伸元素以填滿全部寬度或高度。它也支持讓一個元素填充其他已??吭貨]有占用的剩余空間。
DockPanel 有一個 Dock 附加屬性,因此子元素用4個值來控制她們的??浚篖eft、Top、Right、Bottom 。最后的子元素默認(rèn)填滿所有剩余的空間,除非 DockPanel 的 LastChildFill 屬性為 false 。
<DockPanel>
<Button Content="Button左" DockPanel.Dock="Left"/>
<Button Content="Button右" DockPanel.Dock="Right"/>
<Button Content="Button上" DockPanel.Dock="Top"/>
<Button Content="Button下" DockPanel.Dock="Bottom"/>
</DockPanel>
5.Grid
Grid允許我們通過自定義行列來進(jìn)行布局,這類似于表格。
(1)基本使用
- 通過定義Grid的RowDifinitions和ColumnDifinitions來實現(xiàn)對于表格行和列的定義。
- 元素根據(jù)附加屬性Grid.Row和Grid.Column確定自己的位置。
- 元素根據(jù)附加屬性Grid.RowSpan和Grid.ColumnSpan占用多行/多列空間。
(2)定義列寬與行高
- 固定長度:屬性值為確定的數(shù)字。
- 自動長度:屬性值為 Auto 。
- 比例長度:屬性值為 (number)* ,當(dāng) number 為空時表示占用剩余空間,否則按照不同行/列的 number 值進(jìn)行比例計算后分配空間。
(3)實現(xiàn)拖動方式更改區(qū)域尺寸的功能
使用 GidSplitter 可以實現(xiàn) Grid 行列尺寸重新分配。
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="6"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Button"/>
<Button Grid.Row="1" Content="Button"/>
<GridSplitter Grid.Row="2" HorizontalAlignment="Stretch"/>
<Button Grid.Row="3" Grid.RowSpan="2" Content="Button"/>
</Grid>
6.ScrollViewer
ScrollViewer 是帶有滾動條的面板。在 ScrollViewer 中只能有一個子控件,若要顯示多個子控件,需要先將一個附加的 Panel 控件放置在 ScrollViewer 中,然后可以將子控件放置在該控件中。
- HorizontalScrollBarVisibility 屬性設(shè)置水平滾動條是否顯示,可選值為 Hidde/Visible/Auto ,默認(rèn)值為 Hidden ,一般選擇 Auto 。
- VerticalScrollBarVisibility 屬性設(shè)置垂直滾動條是否顯示,可選值為 Hidde/Visible/Auto ,默認(rèn)值為 Visible ,一般選擇 Auto 。
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Button Content="Button" Width="800" Height="800"/>
</ScrollViewer>
2.1.2內(nèi)容控件
內(nèi)容控件都繼承自 ContentControl ,只能容納一個其他控件作為其內(nèi)容(需要容納多個控件時,使用布局控件存放多個控件),內(nèi)容控件根據(jù)是否帶標(biāo)題加以細(xì)分:
- 不帶標(biāo)題的內(nèi)容控件:共同父類是 ContentControl ,常見的控件有:Label、Button 和 Tooltip 等。
- 帶標(biāo)題的內(nèi)容控件:共同父類是
HeaderedContentControl (繼承自 ContentControl ),常見的控件有:TabItem、GroupBox 和 Expander 等。
2.1.3條目控件
條目控件都繼承自 ItemsControl ,可以顯示一列數(shù)據(jù),條目控件根據(jù)是否帶標(biāo)題加以細(xì)分:
- 不帶標(biāo)題的條目控件:共同父類是 ItemsControl ,常見的控件有:ListBox、Menu 和 StatusBar 等。
- 帶標(biāo)題的條目控件:共同父類是
HeaderedItemsControl (繼承自 ItemsControl ),常見的控件有 MenuItem、TreeViewItem 和 ToolBar等。
2.1.4特殊控件
特殊控件沒有直接的共同父類,這類控件相對比較獨立,常見的控件有:TextBox、TextBlock、Border 和 Image 等。其中,Border 控件是為了實現(xiàn)類似圓角按鈕這樣的功能,WPF 中的自帶按鈕本身沒有圓角這一屬性。
2.1.5綜合示例
<Window x:Class="WPFLearn.Views.Control.ControlDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Views.Control"
mc:Ignorable="d"
Title="ControlDemo"
Height="500" Width="800">
<StackPanel Margin="5">
<GroupBox Header="不帶標(biāo)題的內(nèi)容控件">
<Label Content="我是Labe控件"/>
</GroupBox>
<GroupBox Header="帶標(biāo)題的內(nèi)容控件" Margin="0,10,0,0">
<Expander Header="折疊/展開">
<Label Content="可以被折疊的內(nèi)容"/>
</Expander>
</GroupBox>
<GroupBox Header="不帶標(biāo)題的條目控件" Margin="0,10,0,0">
<ListBox>
<ListBoxItem Content="C++"/>
<ListBoxItem Content="C#"/>
<ListBoxItem Content="Java"/>
</ListBox>
</GroupBox>
<GroupBox Header="帶標(biāo)題的條目控件" Margin="0,10,0,0">
<Menu>
<MenuItem Header="文件">
<MenuItem Header="新建"/>
<Separator/>
<MenuItem Header="保存"/>
<MenuItem Header="另存為"/>
</MenuItem>
</Menu>
</GroupBox>
<GroupBox Header="特殊控件" Margin="0,10,0,0">
<StackPanel>
<TextBox Height="60" BorderBrush="DarkGray"/>
<Image Source="/uires/icon.png" Stretch="None" HorizontalAlignment="Left"/>
<Border BorderBrush="DarkOrange" BorderThickness="1" CornerRadius="5" Height="60" HorizontalAlignment="Left" Padding="5">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Height="30">
<Button Width="90">
按鈕1
</Button>
<Button Width="90" Margin="10,0,0,0">
按鈕2
</Button>
<Button Width="90" Margin="10,0,0,0">
按鈕3
</Button>
</StackPanel>
</Border>
</StackPanel>
</GroupBox>
</StackPanel>
</Window>
2.2控件外觀
XAML 中可以通過三種方式更改控件的外觀:
- 為控件的外觀屬性賦值。
- 為控件創(chuàng)建 Style 。
- 為控件新建 ControlTemplate 。
2.2.1更改外觀屬性值
許多控件具有支持更改控件外觀的屬性,常見外觀屬性有:
- Margin:控件外邊距。
- Padding:控件內(nèi)邊距。
- Background:背景顏色,顏色的屬性值格式支持常見顏色名稱和16進(jìn)制顏色數(shù)值。
- BorderBursh:邊框顏色。
- BorderThickness:邊框厚度。
- …
<Button Margin="10" Background="#FF0000" BorderThickness="1"/>
2.2.2創(chuàng)建Style
WPF 支持通過創(chuàng)建樣式來指定控件的外觀,以實現(xiàn)批量設(shè)置實例外觀的效果。
- 任意元素都有 Resources 屬性,在該屬性元素下可以創(chuàng)建任意可實例化的資源,比如 WPF 程序集中的類型/C#中的基礎(chǔ)類型/…
- 可以在任意 Resources 節(jié)點下用 Style 標(biāo)簽創(chuàng)建樣式。
- Style 元素的 TargetType 屬性可以用兩種方式表達(dá):TargetType = “Button” 和 TargetType = {x:Type Button}。
- 如果 Style 元素沒有顯示指定 TargetType ,則在元素中使用屬性時需要加上 Control 前綴。
- 如果 Style 元素只指定 TargetType,而沒有指定 x:Key,則樣式會自動給樣式定義后該類型的所有元素。如果需要取消引用,需要顯示指定 Style = {x:Null} 。
- 通過使用屬性 BasedOn 實現(xiàn)樣式的繼承。
2.2.3新建ControlTemplate
在 WPF 中,控件的 ControlTemplate 用于定義控件的外觀。可以通過定義新的 ControlTemplate 并將其分配給控件來更改控件的結(jié)構(gòu)和外觀。在許多情況下,模板提供了足夠的靈活性,從而無需自行編寫自定義控件。實現(xiàn)方式:
- 通用:在 Resources 節(jié)點下定義 ControlTemplate 元素,然后給控件的 Template 屬性設(shè)置ControlTemplate 元素的 Key 值。
- 封裝:定義樣式時,設(shè)置 Template 屬性,其值用屬性元素方式表達(dá) ControlTemplate 元素。
2.3.4綜合示例
<Window x:Class="WPFLearn.Views.Control.ControlAppearanceDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Views.Control"
mc:Ignorable="d"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="控件外觀演示" Height="450" Width="800">
<Window.Resources>
<!--###沒有x:Key屬性的Style將應(yīng)用到所有類型為TargetType的實例-->
<!--<Style TargetType="Button">
<Setter Property="FontFamily" Value="Times New Roman"/>
<Setter Property="FontSize" Value="16"/>
</Style>-->
<!--###在Resources節(jié)點下創(chuàng)建樣式,以實現(xiàn)批量設(shè)置效果-->
<Style x:Key="StyleButton" TargetType="{x:Type Button}">
<Setter Property="FontFamily" Value="Times New Roman"/>
<Setter Property="FontSize" Value="16"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="StyleButtonWithControlTemplate" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Name="EllipseSection" Fill="Orange" Width="100" Height="100"/>
<ContentPresenter Content="{TemplateBinding Button.Content}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="EllipseSection" Property="Fill" Value="Yellow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--###單獨定義ControlTemplate,然后再設(shè)置Button.Template屬性-->
<ControlTemplate TargetType="Button" x:Key="ControlTemplateButton">
<Grid>
<Ellipse Name="EllipseSection" Fill="Orange" Width="100" Height="100"/>
<ContentPresenter Content="{TemplateBinding Button.Content}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="EllipseSection" Property="Fill" Value="Yellow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<GroupBox Header="更改外觀屬性值">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<!--###在任意元素的Resources元素下創(chuàng)建資源,以實現(xiàn)值定義效果-->
<FontFamily x:Key="ButtonFontFamily">Times New Roman</FontFamily>
<sys:Double x:Key="ButtonFontSize">16</sys:Double>
</StackPanel.Resources>
<Button FontFamily="Times New Roman" FontSize="16" >
StyledButton1
</Button>
<Button FontFamily="Times New Roman" FontSize="16" Margin="10,0,0,0">
StyledButton2
</Button>
<Button FontFamily="{StaticResource ButtonFontFamily}" FontSize="{StaticResource ButtonFontSize}" Margin="10,0,0,0">
StyledButton3
</Button>
<Button Content="StyledButton4" Margin="10,0,0,0">
<Button.Style>
<Style>
<Style.Setters>
<Setter Property="Control.FontFamily" Value="{StaticResource ButtonFontFamily}"/>
<Setter Property="Control.FontSize" Value="{StaticResource ButtonFontSize}"/>
</Style.Setters>
<Style.Triggers>
<Trigger Property="Control.IsMouseOver" Value="True">
<Setter Property="Control.FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</GroupBox>
<GroupBox Header="創(chuàng)建Style實現(xiàn)批量修改外觀屬性" Margin="0,10,0,0">
<StackPanel Orientation="Horizontal">
<Button Content="StyledButton1"/>
<Button Style="{x:Null}" Content="StyledButton2" Margin="10,0,0,0"/>
<Button Style="{StaticResource StyleButton}" Content="StyledButton3" Margin="10,0,0,0"/>
</StackPanel>
</GroupBox>
<GroupBox Header="創(chuàng)建ControlTemplate實現(xiàn)自定義控件外觀" Margin="0,10,0,0">
<StackPanel Orientation="Horizontal">
<Button Content="NormalButton" VerticalAlignment="Center"/>
<Button Content="NewButton1" Style="{StaticResource StyleButtonWithControlTemplate}" Margin="10,0,0,0"/>
<Button Content="NewButton2" Template="{StaticResource ControlTemplateButton}" Margin="10,0,0,0"/>
</StackPanel>
</GroupBox>
</StackPanel>
</Window>
注解:
1.在 StackPanel.Resources 節(jié)點下定義了 FontFamily 類型資源和 sys:Double 類型資源,然后在 Button 元素中通過標(biāo)記擴(kuò)展語法引用上述資源,引用語法為 FontFamily="{StaticResource ButtonFontFamily}" FontSize="{StaticResource ButtonFontSize}"。通過這種方式,后續(xù)需要修改屬性值時,只需要在資源定義處修改,不必改動到多處。
2.如果需要設(shè)置控件動態(tài)樣式,如鼠標(biāo)移到上面時的樣式、鼠標(biāo)點擊時的樣式,則需要在 Style 元素下使用屬性元素的語法來設(shè)置 Style.Triggers 屬性的值,Trigger 為觸發(fā)器。
3.在窗口根元素 Window 節(jié)點下定義資源,則該頁面所有地方都能引用到該資源。
4.假設(shè) x:Key 為 StyleButton 的樣式?jīng)]有設(shè)置 x:Key 值,則頁面中所有按鈕默認(rèn)都使用了這個樣式,除了顯示給 x:Key 賦值 x:Null 的按鈕。
5.ControlTemplate 的兩種實現(xiàn)方式歸根到底是設(shè)置控件的 Template 屬性,只不過在 Style 元素中設(shè)置該值能實現(xiàn)批量修改控件外觀的功能。
3.綁定
WPF 綁定可以理解為一種關(guān)系,該關(guān)系告訴 WPF 從一個源對象提取一些信息,并將這些信息來設(shè)置目標(biāo)對象的屬性。
- WPF 綁定,必須要有綁定目標(biāo)和綁定數(shù)據(jù)源。
- WPF 綁定語法是在 XAML 中使用 {Binding…} 語句,Binding 可以通過 XAML 語句實現(xiàn)界面與數(shù)據(jù)的耦合,一般情況下,Binding 源是邏輯層的對象,Binding 目標(biāo)是UI層的控件對象。
- WPF 綁定使得原本需要多行代碼實現(xiàn)的功能,現(xiàn)在只需通過簡單的 XAML 代碼就可以完成。
簡單的理解:WPF 綁定特性使得在修改對象的值后,展現(xiàn)對象的界面會自行刷新,不用在代碼中手動更新界面展示。如果使用其他UI框架,則可能的執(zhí)行操作流程是:修改對象的值----更新界面負(fù)責(zé)展示該值的控件的內(nèi)容。通過下面的例子可以體會下 WPF 綁定特性的便捷性。
<Window x:Class="WPFLearn.Views.DataBindingDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Views"
mc:Ignorable="d"
Title="數(shù)據(jù)綁定之綁定控件" Height="300" Width="400"
x:Name="window">
<StackPanel HorizontalAlignment="Stretch" Margin="10">
<ListBox x:Name="ListColor">
<ListBoxItem Content="Blue"/>
<ListBoxItem Content="Red"/>
<ListBoxItem Content="Green"/>
<ListBoxItem Content="Gray"/>
<ListBoxItem Content="Cyan"/>
</ListBox>
<TextBlock Text="{Binding ElementName=ListColor,Path=SelectedItem.Content,Mode=OneWay}" Background="{Binding ElementName=ListColor,Path=SelectedItem.Content,Mode=OneWay}" Margin="0,10,0,0"/>
<TextBox Text="{Binding ElementName=ListColor,Path=SelectedItem.Content,Mode=TwoWay}" Background="{Binding ElementName=ListColor,Path=SelectedItem.Content,Mode=OneWay}" Margin="0,10,0,0"/>
<Button Margin="0,10,0,0">切換焦點</Button>
</StackPanel>
</Window>
public partial class DataBindingDemo : Window
{
public DataBindingDemo()
{
InitializeComponent();
}
}
注解:
1.第一段代碼段為窗口的 XAML 文件內(nèi)容,第二代碼段為窗口的 CS 文件內(nèi)容。
2.該窗口實現(xiàn)的功能:切換列表選擇項,下方的文本顯示框和文本編輯框的內(nèi)容和背景色會跟著改變;修改文本編輯框的內(nèi)容,然后點擊切換焦點的按鈕,列表選中項的內(nèi)容會變?yōu)槲谋揪庉嬁蛑械膬?nèi)容,同時文本顯示框的內(nèi)容、背景顏色與文本編輯框的背景顏色會跟著改變。
3.我們發(fā)現(xiàn)在窗口的 CS 文件中,我們沒有寫任何額外的代碼,比如更新控件內(nèi)容、更新控件背景顏色,我們只是在 XAML 文件中使用了 {Binding…} 這樣的綁定語法,便實現(xiàn)了數(shù)據(jù)同步這一功能,這便是 WPF 綁定的便捷性,也體現(xiàn)出了 WPF 的威力。
3.1數(shù)據(jù)源
WPF 綁定的數(shù)據(jù)源需要具有通知更改功能,有兩種方法設(shè)計這種數(shù)據(jù)源:
- 使用 DependencyObject 類型(依賴屬性)。
- 使用實現(xiàn) INotifyPropertyChanged 接口的類型。
3.2綁定方法
1.ItemsControl
- 在代碼中將集合賦值給控件的 ItemsSource 屬性,在 XAML 文件中就不用給控件的 ItemsSource 屬性賦值。
- 在 XAML 文件中,給控件的 ItemsSource 屬性賦值 “{Binding}” ,然后在代碼初始化窗口時,將集合作為 DataContext 。
- 在 XAML 文件中,首先使用 ObjectDataProvider 對象標(biāo)簽,設(shè)置其 ObjectType、MethodName 屬性,這兩個屬性能夠定位提供數(shù)據(jù)源的方法。然后給控件的 ItemsSource 屬性賦值 “{Binding Source={StaticResource DataList}}” 。其中 DataList 為 ObjectDataProvider 標(biāo)簽中的 x:Key 屬性的值。
2.ContentControl
在 XAML 文件中,給控件的屬性賦值 “{Binding Path=AttributeName}” ,然后在代碼初始化窗口時,將窗口本身賦值給 DataContext 。
3.3綁定模式
控制綁定機(jī)制的關(guān)聯(lián)性,比如單向、雙向還是單次…
1.屬性:Mode 。
2.枚舉值:見下表。
枚舉值 | 意義 |
---|---|
Default | 使用綁定目標(biāo)的默認(rèn) Mode 值。每個依賴項屬性的默認(rèn)值都不同。一般情況下,用戶可編輯控件屬性(例如文本框和復(fù)選框的屬性)默認(rèn)為雙向綁定,而多數(shù)其他屬性默認(rèn)為單向綁定。 |
TwoWay | 源屬性或目標(biāo)屬性的更改可自動更新對方。 |
OneWay | 當(dāng)綁定源(源)更改時,更新綁定目標(biāo)(目標(biāo))屬性。如果無需監(jiān)視目標(biāo)屬性的更改,則使用 OneWay 綁定模式可避免 TwoWay 綁定模式的系統(tǒng)開銷。 |
OneWayToSource | 當(dāng)目標(biāo)屬性更改時更新源屬性。 |
OneTime | 當(dāng)應(yīng)用程序啟動或數(shù)據(jù)上下文更改時,更新綁定目標(biāo)。如果要從源屬性初始化具有某個值的目標(biāo)屬性,并且事先不知道數(shù)據(jù)上下文,則也可以使用此綁定類型。此綁定類型實質(zhì)上是 OneWay 綁定的簡化形式,在源值不更改的情況下可以提供更好的性能。 |
3.4綁定更新
控制綁定機(jī)制觸發(fā)更新的時機(jī),比如失焦、屬性更改…
1.屬性:UpdateSourceTrigger 。
2.枚舉值:見下表。
枚舉值 | 意義 |
---|---|
Default | 綁定目標(biāo)屬性的默認(rèn)更新值,大多數(shù)依賴項屬性的默認(rèn)值都為 PropertyChanged ,而 Text 屬性的默認(rèn)值為 LostFocus 。 |
Explicit | 僅在調(diào)用 UpdateSource 方法時更新綁定源。 |
LostFocus | 當(dāng)綁定目標(biāo)元素失去焦點時,更新綁定源。 |
PropertyChanged | 當(dāng)綁定屬性更改時,立即更新綁定源。 |
3.5示例
<Window x:Class="WPFLearn.Views.DataBinding.BindingDataDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Views.DataBinding"
mc:Ignorable="d"
x:Name="window"
Title="數(shù)據(jù)綁定之綁定對象" Height="300" Width="400">
<Grid >
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel x:Name="PanelStudentInfo">
<StackPanel Orientation="Horizontal">
<TextBlock Text="學(xué)號:"/>
<TextBlock Text="{Binding Path=ID}" Width="100"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Text="姓名:"/>
<TextBlock Text="{Binding Path=Name}" Width="100"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Text="分?jǐn)?shù):"/>
<TextBlock Text="{Binding Path=Score}" Width="100"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button Content="改變姓名" Name="ButtonChangeName" Click="ButtonChangeName_Click"/>
<Button Content="改變分?jǐn)?shù)" Name="ButtonCHangeScore" Click="ButtonCHangeScore_Click" Margin="20,0,0,0"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,20,0,0">
<TextBlock Text="學(xué)校:"/>
<TextBlock x:Name="TextBlockSchool" Text="{Binding Path=School}"/>
<Button x:Name="ButtonChangeSchool" Content="改變學(xué)校" Width="60" Click="ButtonChangeSchool_Click" Margin="10,0,0,0"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
namespace WPFLearn.Views.DataBinding
{
/// <summary>
/// BindingDataDemo.xaml 的交互邏輯
/// </summary>
public partial class BindingDataDemo : Window
{
//類型1:繼承INotifyPropertyChanged的可發(fā)通知消息的類型
private Student student;
//類型2:依賴屬性
public string School
{
get { return (string)GetValue(SchoolProperty); }
set { SetValue(SchoolProperty, value); }
}
public static DependencyProperty SchoolProperty =
DependencyProperty.Register("School", typeof(string), typeof(BindingDataDemo), new PropertyMetadata("清華大學(xué)"));
public BindingDataDemo()
{
InitializeComponent();
student = new Student() { ID = 1, Name = "小紅", Score = 98 };
//綁定方式1:給元素對象設(shè)置DataContext屬性,然后在XAML文件中直接引用
this.PanelStudentInfo.DataContext = student;
this.TextBlockSchool.DataContext = this;
綁定方式2:手寫B(tài)inding TODO:存在問題,沒辦法更新數(shù)據(jù),原因暫時不清楚
//Binding bind = new Binding();
//bind.Source = this;
//bind.Path = new PropertyPath("School");
//bind.Mode = BindingMode.TwoWay;
//bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
//this.TextBlockSchool.SetBinding(TextBlock.TextProperty, bind);
BindingOperations.SetBinding(this.TextBlockSchool, TextBlock.TextProperty, bind);
}
private void ButtonChangeName_Click(object sender, RoutedEventArgs e)
{
student.Name = "小明";
}
private void ButtonCHangeScore_Click(object sender, RoutedEventArgs e)
{
student.Score = 100;
}
private void ButtonChangeSchool_Click(object sender, RoutedEventArgs e)
{
School = "北京大學(xué)";
}
public class Student : INotifyPropertyChanged
{
private int id;
public int ID
{
get { return id; }
set
{
if (id != value)
{
id = value;
OnPropertyChanged(new PropertyChangedEventArgs("ID"));
}
}
}
private string name;
public string Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
}
private double score;
public double Score
{
get { return score; }
set
{
score = value;
OnPropertyChanged(new PropertyChangedEventArgs("Score"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
}
}
注解:
1.Student 類型實現(xiàn)了 INotifyPropertyChanged,因此 Student 類型的 student 字段可以作為綁定數(shù)據(jù)源;而窗口 BindingDataDemo 內(nèi)部添加了 DependencyProperty 類型的依賴屬性 School,因此 School 也可以作為綁定數(shù)據(jù)源。
2.在窗口構(gòu)造函數(shù)中,給控件的數(shù)據(jù)上下文 DataContext 屬性賦值,這樣在 XAML 中,控件就可以直接通過 {Binding Path=XXX} 找到XXX所屬的對象,然后建立綁定關(guān)系。
3.最終,我們在修改函數(shù)中,單純修改內(nèi)部數(shù)據(jù),不用手動更新控件展示值,控件便會自動刷新顯示。
4.模板
在 WPF 中包含三種模板:控件模板、數(shù)據(jù)模板和面板模板,它們都繼承于 FrameworkTemplate 基類。
4.1控件模板
控件模板(System.Windows.Controls.ControlTemplate),即控件外觀,可以通過修改控件模板來自定義控件的外觀表現(xiàn),例如,可以通過修改按鈕的控件模板使按鈕表現(xiàn)為圓形。控件模板控制UI整體外觀。
1.資源定義:ControlTemplate。
2.屬性使用:Template。
3.例子:
<Window x:Class="WPFLearn.Views.Template.ControlTemplateDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Views.Template"
mc:Ignorable="d"
Title="模板之控件模板" Height="450" Width="800">
<Window.Resources>
<ControlTemplate x:Key="RoundButtonTemplate" TargetType="Button">
<Grid>
<Ellipse Name="EllipseSection" Fill="Orange" Width="100" Height="100"/>
<ContentPresenter Content="{TemplateBinding Button.Content}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="EllipseSection" Property="Fill" Value="Yellow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid >
<Button Content="Round Button" HorizontalAlignment="Center" VerticalAlignment="Center" Template="{StaticResource RoundButtonTemplate}"/>
</Grid>
</Window>
4.2數(shù)據(jù)模板
數(shù)據(jù)模板(System.Windows.DataTemplate),即數(shù)據(jù)外觀,用于從一個對象中提取數(shù)據(jù),并在控件中顯示數(shù)據(jù)。只有內(nèi)容控件與條目控件支持?jǐn)?shù)據(jù)模板。數(shù)據(jù)模板控制UI內(nèi)容形式。
1.資源定義:DataTemplate 。
2.屬性使用:ContentTemplate(內(nèi)容控件)、ItemTemplate(條目控件)。
3.例子:
<Window x:Class="WPFLearn.Views.Template.DataTemplateDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Services"
mc:Ignorable="d"
Title="模板之?dāng)?shù)據(jù)模板" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="PersonDataTemplate">
<Border Name="BorderBlue" Margin="3" BorderThickness="3" BorderBrush="Blue" CornerRadius="5">
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock x:Name="TextBlockName" FontWeight="Bold" Text="{Binding Path=Name}"/>
<TextBlock Grid.Row="1" Text="{Binding Path=Age}"/>
</Grid>
</Border>
<DataTemplate.Triggers>
<Trigger SourceName="BorderBlue" Property="IsMouseOver" Value="True">
<Setter TargetName="BorderBlue" Property="Background" Value="LightGray"/>
<Setter TargetName="TextBlockName" Property="FontSize" Value="20"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<Grid Margin="0,0,0,10">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<ListBox x:Name="ListBoxPerson" ItemsSource="{Binding}" HorizontalContentAlignment="Stretch" ItemTemplate="{StaticResource PersonDataTemplate}"/>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,10,0,0">
<Button x:Name="ButtonAddAgeOfFirstItem" Content="遞增第一項年齡值" Height="30" Click="ButtonAddAgeOfFirstItem_Click"/>
<Button x:Name="ButtonDeleteLastItem" Content="刪除第二項" Height="30" Margin="10,0,0,0" Click="ButtonDeleteLastItem_Click"/>
</StackPanel>
</Grid>
</Window>
4.3面板模板
面板模板(System.Windows.Controls.ItemsPanelTemplate),即面板外觀,而面板又是用于進(jìn)行布局的,所以面板的外衣也就是布局的外衣,通過修改面板模板可以自定義控件的布局。例如,ListBox默認(rèn)是自從向下地顯示每一項的,此時可以通過修改面板模板使其自左向右地顯示每一項。面板模板控制UI內(nèi)容布局。
1.資源定義:ItemsPanelTemplate 。
2.屬性使用:ItemsPanel 。
3.例子:
<Window x:Class="WPFLearn.Views.Template.PanelTemplateDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Views.Template"
mc:Ignorable="d"
Title="模板之面板模板" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="PersonDataTemplate">
<Border x:Name="BorderBlue" Margin="3" BorderThickness="3" BorderBrush="Blue" CornerRadius="5">
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock x:Name="TextBlockName" FontWeight="Bold" Text="{Binding Name}"/>
<TextBlock Grid.Row="1" Text="{Binding Age}"/>
</Grid>
</Border>
<DataTemplate.Triggers>
<Trigger SourceName="BorderBlue" Property="IsMouseOver" Value="True">
<Setter TargetName="BorderBlue" Property="Background" Value="LightGray"/>
<Setter TargetName="TextBlockName" Property="FontSize" Value="20"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
<ItemsPanelTemplate x:Key="ListItemsPanelTemplate">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="ListBoxPerson" ItemsPanel="{StaticResource ListItemsPanelTemplate}" ItemTemplate="{StaticResource PersonDataTemplate}"/>
</Grid>
</Window>
5.資源
WPF 資源系統(tǒng)是一種保管一系列對象(如常用的畫刷、樣式或模板)的簡單辦法,從而讓使用者更容易地復(fù)用這些對象。
5.1資源定義
每一個框架級元素( FrameworkElement 或者 FrameworkContentElement )都有一個資源屬性。每一個在資源字典中的資源都有一個唯一不重復(fù)的鍵值( key ),在標(biāo)簽中使用 x:Key 屬性來標(biāo)識它。一般地,鍵值是一個字符串,但你也可以用合適的擴(kuò)展標(biāo)簽來設(shè)置為其他對象類型。非字符鍵值資源使用于特定的WPF 區(qū)域,尤其是風(fēng)格、組件資源以及樣式數(shù)據(jù)等。
5.2資源使用
為了使用 XAML 標(biāo)記中的資源,需要一種引用資源的方法,可以通過兩個標(biāo)記來引用資源:StaticResource 和 DynamicResource 。
- StaticResource :以靜態(tài)方式引用資源。在第一次創(chuàng)建窗口時,一次性地設(shè)置完畢,程序運行過程中資源發(fā)生變化,程序不會更新引用資源的對象。無法實時更新程序,效率高。
- DynamicResource :以動態(tài)方式引用資源。如果資源發(fā)生了改變,程序會重新應(yīng)用資源。可以實時更新程序,效率低。
5.3資源范圍
WPF 提供一個封裝和存取資源的機(jī)制,我們可將資源建立在應(yīng)用程序的不同范圍上。WPF中,資源定義的位置決定了該資源的可用范圍,程序會按照范圍由小到大的順序檢索資源。資源按照范圍分類見下表。
級別 | 說明 |
---|---|
物件級 | 資源定義在普通元素下,該資源只能套用在這個元素及其其子元素。 |
文件級 | 資源定義在Window或Page元素下,該資源可以套用到這個文件中的所有元素。 |
應(yīng)用程序級 | 資源定義在App.xaml中,該資源可以套用到應(yīng)用程序內(nèi)的任何地方。 |
字典級 | 將資源封裝成資源字典定義在資源XAML文件中,該資源可以在套用到其他應(yīng)用程序中。 |
系統(tǒng)級 | 資源檢索的最終層級,我們無法在這層級上自定義資源,系統(tǒng)級資源有系統(tǒng)顏色設(shè)置/字體設(shè)置/屏幕標(biāo)準(zhǔn)尺寸等。 |
5.4綜合示例
1.StaticResource 和 DynamicResource 的區(qū)別
<Window x:Class="WPFLearn.Views.ResourceStyle.ResourceStyleDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFLearn.Views.ResourceStyle"
mc:Ignorable="d"
Title="ResourceStyleDemo" Height="300" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="RedBrush" Color="Red"></SolidColorBrush>
</Window.Resources>
<StackPanel Margin="5">
<StackPanel>
<Button Background="{StaticResource RedBrush}" Margin="5" FontSize="14" Content="Use Static Resource"/>
<Button Background="{DynamicResource RedBrush}" Margin="5" FontSize="14" Content="Use Dynamic Resource"/>
<Button Margin="5" FontSize="14" Content="Change the RedBrush to Yellow" Click="Button_Click"/>
</StackPanel>
</StackPanel>
</Window>
public partial class ResourceStyleDemo : Window
{
public ResourceStyleDemo()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Resources["RedBrush"] = new SolidColorBrush(Colors.Yellow);
}
}
注解: 點擊按鈕后,Use Static Resource 的按鈕背景顏色沒改變,Use Dynamic Resource 的按鈕背景顏色改變。
2.各種級別的資源
物件級和文件級兩個級別的資源之前的示例都有見過,下面是字典級別的,在 App.xaml 引用字典級別資源,相當(dāng)于定義了應(yīng)用級別資源,另外,應(yīng)用級別資源定義同其它級別資源定義一樣,所以應(yīng)用級別資源也不做演示。
<!--CheckBoxStyle.xaml-->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="CheckBoxStyle" TargetType="{x:Type CheckBox}">
<Setter Property="IsChecked" Value="False"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<DockPanel Background="{TemplateBinding Background}" ToolTip="{TemplateBinding Content}" LastChildFill="False" Width="{TemplateBinding Width}">
<Image Margin="0" DockPanel.Dock="Left" x:Name="CheckImage" Stretch="Fill" Source="/Uires/復(fù)選框未選.png" Width="15" Height="15"/>
<TextBlock DockPanel.Dock="Left" Foreground="{TemplateBinding Foreground}" Margin="2,0,0,0" VerticalAlignment="Center" Text="{Binding Content,RelativeSource={RelativeSource TemplatedParent}}"/>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="CheckImage" Property="Source" Value="/Uires/復(fù)選框已選.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
<!--Style.xaml-->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Styles/ButtonStyle.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Styles/CheckBoxStyle.xaml"/>
<ResourceDictionary Source="pack://application:,,,/Styles/OtherStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<!--App.xaml-->
<Application x:Class="WPFLearn.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFLearn"
StartupUri="Views/Control/ControlClassificationDemo.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Styles/Style.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
注解:
1.CheckBoxStyle.xaml 定義了 CheckBox 樣式,Style.xaml 包含所有控件樣式文件,App.xaml 引入 Style.xaml。
2.CheckBoxStyle.xaml 和 Style.xaml 都定義了字典級的資源,在 App.xaml 中定義的資源便是應(yīng)用程序級的資源。
6.樣式
WPF 中通過樣式可以方便地批量設(shè)置控件外觀。
6.1樣式定義
在 XAML 中通過使用 Style 元素定義樣式,既可以在控件元素中定義樣式(樣式用于控件自身),也可以在 Resource 元素中使定義樣式(樣式可以被范圍內(nèi)的所有控件引用)。
在 Style 元素中,通過 Style.Setters 元素定義樣式靜態(tài)內(nèi)容,通過 Style.Triggers (觸發(fā)器)元素定義樣式動態(tài)內(nèi)容。
1.WPF中的觸發(fā)器類型
(1)屬性觸發(fā)器(Property Trigger):當(dāng)Dependency Property的值發(fā)生改變時觸發(fā)。Trigger 和 MultiTriiger 。
(2)數(shù)據(jù)觸發(fā)器(Data Trigger):當(dāng)普通.NET屬性的值發(fā)生改變時觸發(fā)。DataTrigger 和 MultiDataTrigger。
(3)事件觸發(fā)器(Event Trigger):當(dāng)路由事件發(fā)生時觸發(fā)。EventTrigger 。
注解: 觸發(fā)器的 Multi 版本適用多條件的場景,比如設(shè)置復(fù)選框 選中狀態(tài)+鼠標(biāo)移動到上面 的樣式。
6.2樣式使用
1.在控件元素中定義的樣式
不需要顯示引用,效果相當(dāng)直接在控件元素中給各種樣式屬性賦值。
2.在Resource元素中定義樣式
- x:Key 屬性為空的樣式:樣式通過 TargetType 屬性指定控件類型,該類型的所有控件實例都會隱式引用該樣式。如果想要取消引用,需要顯示地給樣式屬性賦值 Style = “{x:Null}” 。
- x:Key 屬性不為空的樣式:需要顯示地給控件元素的樣式屬性賦值 Style = “{StaticResouce StyleKey}” 。
7.路由事件
WPF 除了創(chuàng)建了一個新的依賴屬性系統(tǒng)之外,還用更高級的路由事件功能替換了普通的 .NET 事件。
路由事件是具有更強(qiáng)傳播能力的事件——它可以在元素樹上向上冒泡和向下隧道傳播,并且沿著傳播路徑被事件處理程序處理。
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
<StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
<Button Name="YesButton" Width="Auto" >Yes</Button>
<Button Name="NoButton" Width="Auto" >No</Button>
<Button Name="CancelButton" Width="Auto" >Cancel</Button>
</StackPanel>
</Border>
private void CommonClickHandler(object sender, RoutedEventArgs e)
{
FrameworkElement feSource = e.Source as FrameworkElement;
switch (feSource.Name)
{
case "YesButton":
// do something here ...
break;
case "NoButton":
// do something ...
break;
case "CancelButton":
// do something ...
break;
}
e.Handled=true;
}
8.命令模式
1.概述
在現(xiàn)在的用戶界面中,常常需要從多個不同位置訪問通過函數(shù),即由不同的動作觸發(fā)同樣響應(yīng)。在這種情況下,如果使用路由事件,則需要定義多個事件,然后在這些事件中調(diào)用同個函數(shù),這樣處理會很繁瑣。WPF 使用命令機(jī)制來解決上述問題:WPF 允許在一個地方定義命令,并且在所有的用戶接口控件之中根據(jù)需要地調(diào)用這些命令,例如 Menu,ToolBar 按鈕等,不同動作最終會得到相同的響應(yīng)。
2.WPF 中的命令模型
- 命令:命令表示一個程序任務(wù),并且可跟蹤該任務(wù)是否能被執(zhí)行。然而,命令實際上不包含執(zhí)行應(yīng)用程序的代碼,真正處理程序在命令目標(biāo)中。
- 命令源:命令源觸發(fā)命令,即命令的發(fā)送者。例如 Button、MenuItem 等控件都是命令源,單擊它們都會執(zhí)行綁定的命令。
- 命令目標(biāo):命令目標(biāo)是在其中執(zhí)行命令的元素。如 Copy 命令可以在 TextBox 控件中復(fù)制文本。
- 命令綁定:命令是不包含執(zhí)行程序的代碼的,真正處理程序存在于命令目標(biāo)中。那命令是怎樣映射到處理程序中的呢?這個過程就是通過命令綁定來完成的,命令綁定完成的就是紅娘牽線的作用。
3.WPF 命令的核心
ICommand 接口,該接口定義了命令的工作原理。
9.MVVM
1.概述
MVVM 是 WPF 衍生出的一種優(yōu)秀編程框架(模式),這種模式充分利用了 WPF 的數(shù)據(jù)綁定機(jī)制,最大限度地降低了 XAML 文件和 CS 文件的耦合度,實現(xiàn)了將視圖UI和業(yè)務(wù)邏輯分離的效果。在需要更換界面時,邏輯代碼修改很少,甚至不用修改。
2.定義
- MVVM 編程模式通常被用于 WPF 或 Silverlight 開發(fā),一些現(xiàn)代的 WEB 前端框架也使用了這種模式。
- MVVM 是 Model-View-ViewModel 的縮寫形式。
模型(Model):數(shù)據(jù)對象,負(fù)責(zé)存儲數(shù)據(jù)。
視圖(View):界面對象,負(fù)責(zé)與用戶交互、接收用戶輸入、把數(shù)據(jù)展現(xiàn)給用戶。
視圖模型(View Model):連接對象,負(fù)責(zé)連接 Model 層和 View 層。View Model 不僅僅是 Model 的包裝,它還包含了程序邏輯以及 Model 擴(kuò)展。
3.優(yōu)點
- 低耦合:視圖(View)可以獨立于 Model 變化和修改,一個 ViewModel 可以綁定到不同的 View 上,當(dāng) View 變化的時候 Model 可以不變,當(dāng) Model 變化的時候 View 也可以不變。
- 可重用性:可以把一些視圖邏輯放在一個 ViewModel 里面,讓很多 View 重用這段視圖邏輯。
- 獨立開發(fā):開發(fā)人員可以專注于業(yè)務(wù)邏輯和數(shù)據(jù)的開發(fā)(ViewModel),設(shè)計人員可以專注于頁面設(shè)計,使用 Expression Blend 可以很容易設(shè)計界面并生成XAML代碼。
4.在 WPF 中使用 MVVM 時的特點
- 視圖的 CS 文件包含極少的代碼,其核心邏輯都被放在 View Model 類中,從而使得程序邏輯與視圖耦合度降低。
- ViewModel 類作為 View 的 DataContext 。
- 在 MVVM 下,所有事件和動作都被當(dāng)成命令,如按鈕的點擊操作,此時不是觸發(fā)點擊事件,而是綁定到一個點擊命令,再由命令去執(zhí)行對應(yīng)的邏輯代碼。
5.示例
WPF快速入門系列(8)——MVVM快速入門,這位作者寫的這輪系列文章都很不錯,推薦大家入門 WPF 時去看,地址是WFP快速入門系列 | Learning hard | 博客園。
10.參考資料
1.先說下自己推薦的學(xué)習(xí)路線:
(1)先用1.5倍速看一遍《深入淺出WPF》系列高清視頻教程 | 劉鐵猛 | B站 的視頻。
(2)再認(rèn)真把 WFP快速入門系列 | Learning hard | 博客園 的系列文章都過一遍。
(3)最后找個現(xiàn)有的客戶端程序進(jìn)行模仿練習(xí),用到哪些控件再上網(wǎng)查下具體用法。文章來源:http://www.zghlxwxcb.cn/news/detail-459455.html
2.參考資料大致如下:
《深入淺出WPF》系列高清視頻教程 | 劉鐵猛 | B站
WFP快速入門系列 | Learning hard | 博客園
WPF入門教程系列 | DotNet菜園 | 博客園
WPF基礎(chǔ)之資源 | SmilelyCoding | 博客園
WPF教程 | vue5.com在線教程文章來源地址http://www.zghlxwxcb.cn/news/detail-459455.html
到了這里,關(guān)于WPF基礎(chǔ)知識的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!