如何学习WPF技术?
本文由長(zhǎng)沙DotNET技術(shù)社區(qū)【鄒溪源】整理,共有7544字,閱讀需耗時(shí)15分鐘。
引言
在桌面開發(fā)領(lǐng)域,雖然在某些領(lǐng)域,基于electron的跨平臺(tái)方案能夠?yàn)槲覀儙砟承┍憷?#xff0c;但是由于WPF技術(shù)能夠更好的運(yùn)用Direct3D帶來的性能提升、以及海量Windows操作系統(tǒng)和硬件資源的支持,所以他依然有著得天獨(dú)厚的優(yōu)勢(shì)。
當(dāng)然,選用一門技術(shù),依然看公司的基因土壤和綜合因素或者老板的心血來潮,例如QT也同樣是一門非常不錯(cuò)的跨平臺(tái)圖形界面解決方案。
如何學(xué)習(xí)WPF技術(shù)?
在Quote上有人提出了這樣一個(gè)相同的問題,查看問題,開發(fā)者Srikanth Pagadala如是回答:
1、以了解基礎(chǔ)控件作為學(xué)習(xí)的起步過程:這些控件包括TextBox,Button,TextBlock及其他的,理解這些控件對(duì)外提供的屬性,以及如何使用。
2、了解和使用布局空間:例如Grid、StackPanel、DockerPanel和其他控件,在這一點(diǎn)上,你需要花費(fèi)大量的時(shí)間。同時(shí)你需要學(xué)會(huì)創(chuàng)建復(fù)雜的UI設(shè)計(jì)。
3、了解循環(huán)類型的空間,例如ItemControl控件。
4、了解關(guān)于模板的概念。包括如何定義包含CheckBox的Combox,同時(shí)這個(gè)控件還包含了一張圖片的按鈕,以及如何在ItemsControl中使用不同的模板。
5、理解數(shù)據(jù)綁定的運(yùn)行機(jī)制。嘗試創(chuàng)建一個(gè)MVVM或類似類型的應(yīng)用程序。
6、創(chuàng)建一個(gè)典型的控件,探索DependencyProperties(依賴屬性)和AttachedProperties(附加屬性)。
7、創(chuàng)建一個(gè)樣式資源,理解如何給控件設(shè)計(jì)樣式。
除此之外,還有其他開發(fā)者給出了補(bǔ)充回答:
1、學(xué)習(xí)控件的數(shù)據(jù)綁定過程,在DataGrid上實(shí)現(xiàn)數(shù)據(jù)綁定。
2、學(xué)習(xí)和實(shí)現(xiàn)INotifyPropertyChanged類。查看如何實(shí)現(xiàn)
3、學(xué)習(xí)Observable Collection。該類型的集合廣泛使用于數(shù)據(jù)集合綁定方面,同時(shí)也提供了數(shù)據(jù)改變通知的機(jī)制。
4、使網(wǎng)格上的列可編輯。用文本控件(用戶項(xiàng)目模板)替換列。為每個(gè)捕獲文本更改事件的列創(chuàng)建一個(gè)屬性。在文本控件上使用綁定類型。嘗試捕獲您在后端在網(wǎng)格上所做的更改。
5、成功將數(shù)據(jù)控件中的文本控件與后端屬性綁定后,請(qǐng)?jiān)谕豁?yè)面上創(chuàng)建網(wǎng)格的副本。嘗試同步這兩個(gè)網(wǎng)格。例如,您在第一個(gè)網(wǎng)格中所做的每個(gè)更改都必須在第二個(gè)網(wǎng)格中自動(dòng)更新。
網(wǎng)站“https://www.wpf-tutorial.com/”是一個(gè)專門用于學(xué)習(xí)WPF的網(wǎng)站,通過這個(gè)網(wǎng)站,可以快速的入門WPF。
由于WPF技術(shù)已經(jīng)比較熟悉,所以書籍也比較多,網(wǎng)友推薦來自劉鐵猛老師的《深入淺出WPF》這本書,而我通過Kindle則看到了一本比較有意思的書《葵花寶典-WPF自學(xué)手冊(cè)》,這本書寫得比較生動(dòng),通過故事的形式講了WPF的許多技術(shù)原理,無形中讓我對(duì)WPF的概念有了許多新的認(rèn)識(shí)。當(dāng)然,這本書已經(jīng)有點(diǎn)年頭了。
WPF的常用控件
| 控件類型 | 控件名稱 | 控件說明 | 鏈接地址 |
|:—-:|:—-:|:—-:|:—-:|:—-:|:—-:|:—-:|:—-:|
| 組件 | Window | 窗口 |?查看示例?|
| | Page | 頁(yè)面 |?查看示例?|
| | NavigationWindow | 導(dǎo)航窗口 |?查看示例?|
| | Frame | |?查看示例?|
| 常規(guī)控件 | Button | 按鈕控件,提供Content作為內(nèi)容 |?查看示例?|
| | TextBox | 文本框控件,用以輸入文本 |?查看示例?|
| | TextBlock | 文本塊,用以顯示文本 |?查看示例?|
| | Label | 標(biāo)簽,用以顯示文本 |?查看示例?|
| | ProgressBar | 進(jìn)度條 |?查看示例?|
| | ToggleButton | 一種可以設(shè)置開關(guān)三態(tài)的按鈕 |?查看示例?|
| | Image | 圖像控件,通過Source設(shè)置資源路徑 |?查看示例?|
| | CheckBox | 勾選框,可以設(shè)置是否勾選的三種狀態(tài) |?查看示例?|
| | RichTextBox | 富文本框,可以多種格式顯示和輸入文本 |?查看示例?|
| | TreeView | 樹視圖,以樹狀圖的形式顯示綁定內(nèi)容,可以顯示是否勾選三態(tài)。|?查看示例?|
| | WebBrowser | 瀏覽器,基于IE內(nèi)核的瀏覽器控件 |?查看示例?|
| | Calendar | 日歷控件 |?查看示例?|
| | ComboBox | 下拉列表 |?查看示例?|
| | ContentControl | 內(nèi)容控件 |?查看示例?|
| | Expander | 擴(kuò)展器,可以顯示和折疊面板內(nèi)的元素 |?查看示例?|
| | GroupBox | 分組框 |?查看示例?|
| | StatusBar | 狀態(tài)欄,用于在頁(yè)面下方顯示狀態(tài)信息。|?查看示例?|
| | DateTimePicker | 時(shí)間控件,可以設(shè)置時(shí)間狀態(tài)。|?查看示例?|
| | DocumentViewer | 文檔查看器 |?查看示例?|
| | RadioButton | 單選按鈕 |?查看示例?|
| | ScollViewer | 滾動(dòng)視圖 |?查看示例?|
| | ScollBar | 滾動(dòng)條 |?查看示例?|
| | Separator | 分隔器 |?查看示例?|
| | ToolBar | 工具條 |?查看示例?|
| | Slider | |?查看示例?|
| | Menu | 菜單 |?查看示例?|
| | MediaElement | 多媒體控件 |?查看示例?|
| | PasswordBox | 密碼輸入框 |?查看示例?|
| | TabControl | 選項(xiàng)卡 |?查看示例?|
| | ToolBarTray | 工具條 |?查看示例?|
| | WindowsFormsHost | 用以承載WinForm |?查看示例?|
| | Border | 邊框 |?查看示例?|
| 數(shù)據(jù)控件 | ListView | 列表視圖 |?查看示例?|
| | DataGrid | 數(shù)據(jù)表 |?查看示例?|
| | ListBox | 列表框 |?查看示例?|
| 布局 | WrapPanel | 可變面板 |?查看示例?|
| | StackPanel | 固定面板 |?查看示例?|
| | DockerPanel | 停靠面板 |?查看示例?|
| | Grid | 表格布局 |?查看示例?|
| | UniformGrid | 統(tǒng)一分布表格布局 |?查看示例?|
|?查看示例?| Canvas | 畫布 |?查看示例?|
| 圖形 | Point | 點(diǎn) |?查看示例?|
| | Line | 線 |?查看示例?|
| | Path | 路徑 |?查看示例?|
| | Polygon | 多邊形 |?查看示例?|
| | Polyline | 多段線 |?查看示例?|
| | Rectangle | 矩形 |?查看示例?|
| | Shape | 畫筆 |?查看示例?|
| | Rectangle | 矩形 |?查看示例?|
| | Ellipse | 橢圓 |?查看示例?|
WPF的XAML語(yǔ)法
概述
在WPF技術(shù)中引入的XAML語(yǔ)法算是該技術(shù)的一大特色,也是被學(xué)習(xí)者視同為學(xué)習(xí)路徑陡峭的“罪魁禍?zhǔn)住薄T蚴窃谇岸思夹g(shù)飛速發(fā)展的今天,HTML的語(yǔ)法體系由于更早的被開發(fā)者接受,所以也自然而然更容易成為開發(fā)者的首選。
而XAML是一種脫胎于XML,并吸收了HTML的精華的語(yǔ)法體系,是一種界面描述語(yǔ)言,XML語(yǔ)法本身相對(duì)而言較為臃腫的體系,看似成為了他的歷史負(fù)擔(dān),但是其實(shí)倒也沒那么復(fù)雜,通過幾個(gè)簡(jiǎn)單的示例,其實(shí)就足夠掌握這門新的語(yǔ)法體系了。例如,使用這樣的語(yǔ)法,完全可以平滑過渡到這樣的語(yǔ)法體系。(部分標(biāo)簽其實(shí)只是大小寫不同)。當(dāng)然,在XAML中熟練編寫樣式,確實(shí)需要花一點(diǎn)點(diǎn)時(shí)間。
在WPF中,通過XAML定義面向用戶交互層的界面,然后編譯成baml運(yùn)行,后端則使用C#或VB.NET這樣的CLR語(yǔ)法來實(shí)現(xiàn)邏輯交互。
XAML的語(yǔ)法定義
XAML的根元素定義
根元素定義是定義XAML的命名空間。
| 1 2 3 | <Pagexmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
XAML的屬性語(yǔ)法
通過xaml定義按鈕,并設(shè)置文本為 helloworld 。這種寫法在官方文檔中稱為“屬性語(yǔ)法”,即直接在XAML中對(duì)屬性進(jìn)行設(shè)置。
| 1 | <Button Background="Blue" Foreground="Red" Content="hello world"/> |
XAML的屬性元素語(yǔ)法
通過xaml定義按鈕,并設(shè)置其背景為藍(lán)色畫筆,字體顏色為紅色畫筆,內(nèi)容 為helloworld。這種寫法在官方文檔中稱為“屬性元素語(yǔ)法”。
| 1 2 3 4 5 6 7 8 9 10 11 | <Button><Button.Background><SolidColorBrush Color="Blue"/></Button.Background><Button.Foreground><SolidColorBrush Color="Red"/></Button.Foreground><Button.Content>hello world</Button.Content> </Button> |
XAML的集合語(yǔ)法
定義按鈕的顏色為紅色和藍(lán)色漸變色,內(nèi)容為helloworld。這種稱為“集合語(yǔ)法”。
| 1 2 3 4 5 6 7 | <LinearGradientBrush><LinearGradientBrush.GradientStops><!-- no explicit new GradientStopCollection, parser knows how to find or create --><GradientStop Offset="0.0" Color="Red" /><GradientStop Offset="1.0" Color="Blue" /></LinearGradientBrush.GradientStops> </LinearGradientBrush> |
XAML的樣式定義
通過屬性語(yǔ)法來定義按鈕的外觀
樣式定義使用?標(biāo)簽,然后在中間對(duì)樣式的內(nèi)容進(jìn)行定義。
例如,以下表示通過XAML語(yǔ)法對(duì) ToggleButton 按鈕定義了一個(gè)命名為 ToggleLikeButtonStyle 的樣式。
| 1 2 3 4 5 6 7 8 9 10 11 12 | ?<Style TargetType="ToggleButton" x:Key="ToggleLikeButtonStyle"><Setter Property="Margin"? ?Value="4" /><Setter Property="FontWeight" Value="Black"/><Setter Property="Foreground"? Value="Black" /><Setter Property="BorderThickness" Value="0"/><Setter Property="IsThreeState" Value="False"></Setter></Style> |
WPF中的模板Template
WPF中的控件可以通過模板 Template 的形式來定義其內(nèi)容,使得開發(fā)者能夠通過 XAML 靈活的對(duì)控件的外觀進(jìn)行擴(kuò)展。例如,如下定義了一個(gè) Template,這個(gè)控件模板將會(huì)對(duì)控件(Button)定義填充制定顏色。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ?<Setter Property="Template"><Setter.Value><ControlTemplate><Border BorderThickness="0" CornerRadius="3"><Border.Background><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"><GradientStop Color="#4696F2" Offset="0.5"/></LinearGradientBrush></Border.Background><ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" /></Border></ControlTemplate></Setter.Value></Setter> |
XAML中的觸發(fā)器Triggers
傳統(tǒng)的WinForm開發(fā)者習(xí)慣于通過事件的機(jī)制對(duì)按鈕的外觀進(jìn)行定義,而在WPF中,則可以通過屬性的形式對(duì)外觀進(jìn)行設(shè)置,這使得開發(fā)者更能夠?qū)懗龈哔|(zhì)量的代碼。
例如,如下代碼通過定義觸發(fā)器,設(shè)置控件(控件為 ToggleButton),當(dāng)控件的勾選狀態(tài)屬性為“IsChecked” 時(shí),其邊框填充色為#4696F2顏色。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Setter Property="Border.Background" TargetName="PART_Background" <Setter.Value><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"><GradientStop Color="#4696F2" Offset="0.5"/></LinearGradientBrush></Setter.Value></Setter><Setter Property="Width" TargetName="PART_Background" Value="60"></Setter><Setter Property="Content" TargetName="contextPresenter" Value="已點(diǎn)贊"></Setter><Setter Property="Visibility" TargetName="contextPresenter" Value="Visible"></Setter><Setter Property="Visibility" TargetName="contextImage" Value="Hidden"/></Trigger> </ControlTemplate.Triggers> |
部分完整代碼
在上述事例中,共定義了兩個(gè)按鈕的樣式,分別是:
FlatButtonStyle,這是個(gè)圓角按鈕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <Style TargetType="Button" x:Key="FlatButtonStyle"><Setter Property="Margin"? ?Value="4" /><Setter Property="FontWeight" Value="Black"/><Setter Property="Foreground"? Value="Black" /><Setter Property="BorderThickness" Value="0"/><Setter Property="Template"><Setter.Value><ControlTemplate><Border BorderThickness="0" CornerRadius="3"><Border.Background><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"><GradientStop Color="#4696F2" Offset="0.5"/></LinearGradientBrush></Border.Background><ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" /></Border></ControlTemplate></Setter.Value></Setter></Style> ToggleLikeButtonStyle,這是一個(gè)點(diǎn)贊按鈕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <Style TargetType="ToggleButton" x:Key="ToggleLikeButtonStyle"><Setter Property="Margin"? ?Value="4" /><Setter Property="FontWeight" Value="Black"/><Setter Property="Foreground"? Value="Black" /><Setter Property="BorderThickness" Value="0"/><Setter Property="IsThreeState" Value="False"></Setter><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type ToggleButton}"><Border BorderThickness="0" CornerRadius="3" Name="PART_Background"><Border.Background><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"><GradientStop Color="#525252" Offset="0.5"/></LinearGradientBrush></Border.Background><Grid><ContentPresenter x:Name="contextPresenter" Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" /><Image x:Name="contextImage" Width="24" Height="24" Source="assests/thumbs-up-outline.png" HorizontalAlignment="Center" VerticalAlignment="Center"/></Grid></Border><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="True"><Setter Property="Border.Background" TargetName="PART_Background"><Setter.Value><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"><GradientStop Color="#4696F2" Offset="0.5"/></LinearGradientBrush></Setter.Value></Setter><Setter Property="Width" TargetName="PART_Background" Value="60"></Setter><Setter Property="Content"? TargetName="contextPresenter" Value="已點(diǎn)贊"></Setter><Setter Property="Visibility"? TargetName="contextPresenter" Value="Visible"></Setter><Setter Property="Visibility" TargetName="contextImage" Value="Hidden"/></Trigger><Trigger Property="IsChecked" Value="False"><Setter Property="Border.Background" TargetName="PART_Background"><Setter.Value><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"><GradientStop Color="#525252" Offset="0.5"/></LinearGradientBrush></Setter.Value></Setter><Setter Property="Width" TargetName="PART_Background" Value="40"></Setter><Setter Property="Visibility"? TargetName="contextPresenter" Value="Hidden"></Setter><Setter Property="Visibility" TargetName="contextImage" Value="Visible"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter> </Style>
XAML的標(biāo)記擴(kuò)展
通過了解WPF的常用控件,我們可以知道自己需要使用的控件有哪些屬性,并能使用 XAML 語(yǔ)法對(duì)相應(yīng)的屬性進(jìn)行設(shè)置,這種設(shè)置方法有別于通過C#代碼的形式進(jìn)行定義的方法,在 XAML中的屬性稱為 “標(biāo)記”。標(biāo)記使用 “{}” 花括號(hào),編譯器通過該花括號(hào)將語(yǔ)法和XAML語(yǔ)法進(jìn)行區(qū)分。
例如:
| 1 | ?HeaderTemplate="{DynamicResource StretchedHeaderTemplate}" |
標(biāo)記值的轉(zhuǎn)換與TypeConverters
在進(jìn)行標(biāo)記值轉(zhuǎn)換時(shí),有時(shí)候需要使用TypeConverters實(shí)現(xiàn)類型轉(zhuǎn)換。例如,在上述示例代碼中,可以看到使用了字符串“#525252”來定義顏色,在內(nèi)部就是實(shí)現(xiàn)了從字符串到 Color 類的轉(zhuǎn)換過程。限于篇幅有限,此處就暫時(shí)略過。
XAML中內(nèi)置特殊標(biāo)記擴(kuò)展
x:Type:特定類型
1 <object property="{x:Type prefix:typeNameValue}" .../> x:Static:使用靜態(tài)值。
1 <object property="{x:Static prefix:typeName.staticMemberName}" .../> x:Null:使用空對(duì)象定義為屬性值。
1 <object property="{x:Null}" .../> x:Array:使用數(shù)組對(duì)象。
1 2 3 <x:Array Type="typeName">arrayContents </x:Array>
常見的標(biāo)記擴(kuò)展
StaticResource:通過替換已定義資源的值來為屬性提供內(nèi)容,該資源標(biāo)記在XAML加載時(shí)自動(dòng)執(zhí)行。靜態(tài)資源無法通過在XAML語(yǔ)法體系中對(duì)其引用關(guān)系進(jìn)行前向引用,意味著無法通過多層級(jí)關(guān)系定義可復(fù)用的樣式資源,如果需要這樣做,則需要使用DynamicResource。
| 1 | <object property="{StaticResource key}" .../> |
DynamicResource:在運(yùn)行時(shí)為資源提供內(nèi)容。
| 1 | <object property="{DynamicResource key}" .../> |
Binding:在運(yùn)行時(shí)為使用數(shù)據(jù)上下文為數(shù)據(jù)提供內(nèi)容。
| 1 2 3 4 5 6 7 8 | <object property="{Binding}" .../> -or- <object property="{Binding bindProp1=value1[, bindPropN=valueN]*}" ... /> -or- <object property="{Binding path}" .../> -or <object property="{Binding path[, bindPropN=valueN]*}" .../> |
RelativeSource:提供了可在運(yùn)行時(shí)對(duì)象樹中導(dǎo)航幾個(gè)可能的關(guān)系的?Binding?的源信息。
| 1 | <Binding RelativeSource="{RelativeSource modeEnumValue}" .../> |
TemplateBinding:使控件模板能夠使用模板化屬性的值,這些屬性來自于將使用該模板的類的對(duì)象模型定義屬性。
| 1 | <object property="{TemplateBinding sourceProperty}" .../> |
ColorConvertedBitmap:提供一種方法,用于指定沒有嵌入的配置文件的位圖源。顏色上下文/配置文件由 URI 指定,與映像源 URI 相同。
| 1 | <object property="{ColorConvertedBitmap imageSource sourceIIC destinationIIC}" .../> |
ComponentResourceKey和TemplateResourceKey:
| 1 | <object x:Key="{ComponentResourceKey {x:Type targetTypeName}, targetID}" .../> |
XAML資源復(fù)用
在開發(fā)過程中,我們可以直接在按鈕上進(jìn)行按鈕模板的定義,例如下面的代碼。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <Button Width="40" Height="40" Style="{DynamicResource CubeImageButtonStyle}" Click="Button_Click" Content="點(diǎn)贊"><Button.Background><ImageBrush ImageSource="/assests/favicon.png" Stretch="Fill"/></Button.Background></Button><Setter Property="Template"<Setter.Value><ControlTemplate><Border BorderThickness="0" CornerRadius="3"><Border.Background><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"><GradientStop Color="#4696F2" Offset="0.5"/></LinearGradientBrush></Border.Background><ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" /></Border></ControlTemplate></Setter.Value></Setter></Style></Window.Resources><Grid> <Button Grid.Column="0" Grid.Row="1" Style="{StaticResource FlatButtonStyle}" HorizontalAlignment="Center" VerticalAlignment="Top" Width="48" Height="16" FontSize="10" Background="#4696F2" Content="獲取"></Button></Grid> |
這樣的代碼在界面比較簡(jiǎn)單時(shí),還無所謂,但是隨著控件的樣式越來越復(fù)雜,可能會(huì)成為一團(tuán)亂麻,這對(duì)于追求優(yōu)雅代碼的我們來說,可能是難以忍受的,所以往往會(huì)使用資源引用來完成。
StaticResource
例如,我們可以在當(dāng)前頁(yè)面代碼中定義對(duì)應(yīng)的樣式,這種樣式可以使用 StaticResource 的形式引入。但是這樣的引用形式,沒有對(duì)象圖的訪問權(quán)限,意味著無法訪問資源依賴的其他資源。
| 1 2 3 4 5 6 7 | ?<Window.Resources> <Style TargetType="Button" x:Key="FlatButtonStyle">?<Setter Property="Margin"? ?Value="4" /><Setter Property="FontWeight" Value="Black"/><Setter Property="Foreground"? Value="Black" />? ??<Setter Property="BorderThickness" Value="0"/> </Window.Resources> |
DynamicResource
將上述代碼中的{StaticResource FlatButtonStyle} 改成{StaticResource FlatButtonStyle}則會(huì)在運(yùn)行時(shí)加載樣式,并可以訪問相應(yīng)的對(duì)象圖。
當(dāng)然,這樣的更改意義不大,如果該FlatButtonStyle引用了其他樣式或元素,會(huì)發(fā)生作用。
| 1 2 3 | <Grid <Button Grid.Column="0" Grid.Row="1" Style="{StaticResource FlatButtonStyle}" HorizontalAlignment="Center" VerticalAlignment="Top" Width="48" Height="16" FontSize="10" Background="#4696F2" Content="獲取"></Button></Grid> |
注意事項(xiàng)
1、由于XAML語(yǔ)法脫胎于XML語(yǔ)法,而XML語(yǔ)法中本身對(duì)某些輸入字符,如“<>”存在限制,所以在XAML中也會(huì)出現(xiàn)這類問題,并會(huì)被Visual Studio檢測(cè)出錯(cuò)誤而無法編譯,需要使用UTF-8編碼進(jìn)行轉(zhuǎn)換。
用戶控件和自定義控件
用戶控件
而用戶控件,使用于控件組合的場(chǎng)景。
自定義控件
在筆者進(jìn)行開發(fā)時(shí),總是思考究竟是使用用戶控件,還是自定義控件,后來在閱讀《葵花寶典-WPF自學(xué)手冊(cè)》這本書中,終于得以大徹大悟。
作者指出:“不要被控件的外觀所欺騙,要考慮其內(nèi)在本質(zhì)”。即思考控件的基本特征,首先想到該控件的行為與原有控件的行為是否相似,如果能夠找到,則修改原有控件,而不是定義一個(gè)控件。尤其是在XAML語(yǔ)法中,能夠通過Content 模型和模板、附加屬性的運(yùn)用,使得自定義控件的用途得到了進(jìn)一步縮減,只有當(dāng)實(shí)在萬(wàn)不得已時(shí),在定義自定義控件。
作者給出了使用自定義控件的分析思路:
例如,在示例代碼*ToggleLikeButtonStyle *中,我實(shí)現(xiàn)了一個(gè)點(diǎn)贊和取消點(diǎn)贊的狀態(tài),則使用了ToggleButton來完成,就沒必要使用 Button 擴(kuò)展出一個(gè)是否點(diǎn)贊的狀態(tài)了。
而如果我們需要實(shí)現(xiàn)的功能有這么復(fù)雜,那大概使用傳統(tǒng)的控件就無法實(shí)現(xiàn),就得使用自定義控件了。(點(diǎn)擊查看示例代碼)
作者定義了自定義控件 ButtonEx,并實(shí)現(xiàn)了依賴屬性 ButtonType,見【依賴屬性】,并定義了不同類型的樣式特征。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ?<Trigger Property="ButtonType" Value="Icon"><Setter Property="Cursor" Value="Hand"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type controls:ButtonEx}"><Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"><Image x:Name="Img" VerticalAlignment="Center" HorizontalAlignment="Center" Source="{TemplateBinding Icon}" Stretch="None"/></Border><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Opacity" Value="0.8"/></Trigger><Trigger Property="IsPressed" Value="True"><Setter Property="Opacity" Value="0.9"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Trigger> |
使用時(shí),只需這樣設(shè)置,即可實(shí)現(xiàn)不同類型的按鈕外觀。
| 1 | ?<controls:ButtonEx Icon="/Images/search.png"? Margin="10" ButtonType="Icon"/> |
屬性和事件
依賴屬性
依賴屬性是為既有WPF控件對(duì)象定義自定義屬性,以便支持其擴(kuò)展,例如在上述自定義控件的示例中,就定義了依賴屬性 ButtonType,實(shí)現(xiàn)了不同類型的按鈕外觀。
| 1 2 3 4 5 6 7 8 | public ButtonType ButtonType{get { return (ButtonType)GetValue(ButtonTypeProperty); }set { SetValue(ButtonTypeProperty, value); }}public static readonly DependencyProperty ButtonTypeProperty = DependencyProperty.Register(“ButtonType”,?typeof(ButtonType),?typeof(ButtonEx),?new?PropertyMetadata(ButtonType.Normal)); |
附加屬性
按照官方的說法就是“附加屬性旨在用作可在任何對(duì)象上設(shè)置的一類全局屬性”,例如,DockPanel面板中的子對(duì)象,繼承了來自于容器對(duì)象的附加屬性,使得其能夠在父對(duì)象中實(shí)現(xiàn)停靠的功能。
| 1 2 3 | <DockPanel><CheckBox DockPanel.Dock="Top">Hello</CheckBox> </DockPanel> |
路由事件
基本定義
假設(shè)我們定義了幾個(gè)這樣的控件。
| 1 2 3 4 5 6 7 | <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> |
實(shí)現(xiàn)了這樣的界面
路由事件就是針對(duì)這組元素樹中多個(gè)元素調(diào)用處理程序的事件。當(dāng)我們點(diǎn)擊了按鈕Button時(shí),將會(huì)觸發(fā) Button=>StackPanel=>Border的事件路由,而不是像WinForm應(yīng)用一樣,只能觸發(fā)最上層的Button的按鈕點(diǎn)擊事件。
路由策略
冒泡事件(官方稱為浮升,這個(gè)翻譯有點(diǎn)。。):調(diào)用事件源上的事件處理程序。路由事件隨后會(huì)路由到后續(xù)的父級(jí)元素,直到到達(dá)元素樹的根。大多數(shù)路由事件都使用浮升路由策略。浮升路由事件通常用于報(bào)告來自不同控件或其他 UI 元素的輸入或狀態(tài)變化。
直接:只有源元素本身才有機(jī)會(huì)調(diào)用處理程序以進(jìn)行響應(yīng)。通過使用?EventSetter?和?EventTrigger使用來設(shè)置處理程序。例如,可以使用RoutedEventArgs的Handled,設(shè)置為 true 將事件標(biāo)記為已處理,將 “停止” 路由用于隧道路由或冒泡路由。
1 2 3 4 5 6 7 8 9 void MakeButton2() {Button b2 = new Button();b2.Click += new RoutedEventHandler(Onb2Click2); } void Onb2Click2(object sender, RoutedEventArgs e) {//logic to handle the Click event } 隧道:最初將調(diào)用元素樹的根處的事件處理程序。隨后,路由事件將朝著路由事件的源節(jié)點(diǎn)元素(即引發(fā)路由事件的元素)方向,沿路由線路傳播到后續(xù)的子元素。
WPF中約定,隧道路由事件的名稱以單詞“Preview”開頭。輸入事件通常成對(duì)出現(xiàn),一個(gè)是浮升事件,另一個(gè)是隧道事件。例如,如下圖所示,假設(shè)按鈕2為觸發(fā)事件的源。
1、處理Border根元素的隧道事件PreviewMouseDown
2、處理StackPanel面板的隧道事件PreviewMouseDown.
3、處理Button按鈕的隧道事件的PreMouseDown。
4、處理Button按鈕的MouseDown事件。
5、處理StackPanel的MouseDown事件。
6、處理Border的MouseDown事件。
總結(jié)
WPF是一個(gè)非常龐大的技術(shù)體系,以上學(xué)習(xí)路徑僅供開發(fā)者進(jìn)行簡(jiǎn)單的入門,由于篇幅有限,對(duì)于標(biāo)記擴(kuò)展還需要進(jìn)一步理解透徹,以及格式轉(zhuǎn)換、圖形繪制、數(shù)據(jù)綁定、MVVM等內(nèi)容未能一一描述。
如果果想要對(duì)WPF進(jìn)一步了解,最好通過系統(tǒng)的學(xué)習(xí)相關(guān)知識(shí),除了前面提到的網(wǎng)站和幾本書,最好的入門網(wǎng)站依然是微軟官方文檔。
總結(jié)
以上是生活随笔為你收集整理的如何学习WPF技术?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 漫谈Linux文档属性、拥有者、群组、权
- 下一篇: gRPC in ASP.NET Core