WPF入門教程系列(一) 建立你的第一個WPF專案
WPF基礎知識
快速學習絕不是從零學起的,良好的基礎是快速入手的關鍵,下面先為大家摞列以下自己總結的學習WPF的幾點基礎知識:
1) C#基礎語法知識(或者其他.NET支援的語言):這個是當然的了,雖然WPF是XAML配置的,但是總還是要寫程式碼的,相信各位讀者應該也都有這個基礎了。
2) HTML語言:雖然WPF是窗體程式但是由於使用的XAML語言,如果以前接觸過HTML、XHTML、ASP.NET之路的東西的話會,接受這些標籤會很有幫助的,如果以前一直是從事win form開的人來說可能就要適應一下了。
3) 對C#中的代理、事件要做到熟練掌握,在.NET 3.0 版本後有增加了Routed Events,要想日後不糊塗,這個是基礎。
4) 有一定的winform或ASP.NET經驗,主要是對控制元件事件的處理要有寫了解。
5) 擁有良好的面向物件的思想:思想是語言的昇華(本人的OO思想完全是Java中領悟來的)。在WPF中,經常要靈活運用各種繼承關係、多型、過載等,因此一定要把基礎知識打牢固。
6) DataBinding要有所瞭解:Binding是WPF的一大亮點,在接觸它以前如果接觸國ADO.NET裡面的DataBinding的話對相對起來會容易接受一點,雖然這兩個有一定的不同。
7) 對設計模式要有一定的瞭解:當然是越深入越好了,在實際專案中,各種設計模式經常交融使用。
快速的識別併合理的運用,無論是在開發還是除錯時都是非常高效的。另外,WPF存在的初衷即是表現與邏輯的鬆耦合,最普遍的情況就是XAML作為表現層,背後.cs檔案作為邏輯層。因此,日後在從事專案工作時,要時刻謹記這一點,千萬不可背道而馳。
不要為了凸顯自己的某一些程式碼特長而將各種邏輯混寫在一起,這樣非常不實際的,這一點都在校生應該尤為重要。
8) 對XML的理解:XAML也是XML,對XML的理解絕對有助於快速的接受和使用XAML,並不需要多XML有多麼高深的見解。
WPF入手練習基礎環境
開發環境:VS 2008
資料庫:本機SQL Server 2005(這裡給大家一個提醒,如果大家的機子是Windows XP的話,無論是home 或是 professional.
一定不要安裝SQL Server 2005 Enterprise Edition,在《安裝 SQL Server 2005 的硬體和軟體要求》中“作業系統要求”列表有寫到2005 Enterprise Edition 不支援 XP),建議安裝Developer Edition,一定
WPF練習內容
具備以上基礎條件後,開始入手練習,大家不要抱怨入手練習有寫難度,畢竟是快速入門要有一定的跳躍性:
我們要做一個WPF程式,功能很簡單:
1)從資料庫(本地資料庫(local)/AdventureWorks中的person.contact表中提取使用者的ContactID,FirstName,LastName,EmailAddress資料,展示到Form上的一個ListView上。(由於是WPF練習,對於ADO.NET相關的東西在此不做介紹,知識使用而已)
2) 當滑鼠或其他裝置選中結果某一項記錄時,在List框下面展示出細節。
3) 修改其中的內容後,結果聯動更新到List框及資料庫中。
想象以下這樣一個東西如果在以前使用winform實現會是什麼樣子呢?
應該會寫不少的方法、屬性用於介面之間及介面與資料庫之間的聯動。
今天這個練習就先展示以下WPF的技術亮點之一:
DataBinding。在製作過程中,還會為大家不斷接受一些控制元件、佈局等相關知識和技巧,部分相關的知識內容與此練習關係不大的,我將會用淺灰色字型帶過,對於熟悉這部分內容的讀者可以直接跳過。
建立一個WPF專案
開啟VS 2008 新建一個WPF應用程式
WPF介面佈局
首先會看到一個靚麗的小方框,將滑鼠放在方框的邊緣點選就會產生相應的分割線。
現在我們要做的內容需要將窗體分成三行,可以先隨便分割一下,以後在調整相互的大小。這時候會注意到下方的XML程式碼區域。每個RowDefinition作為一個行被定義出來
這裡先給大家接受以下高度、寬度的幾種定義方式(寫過HTML的人可以跳過去了):
絕對尺寸(Absolut sizing):就是給一個實際的數字,像現在例子中那樣
自動(Autosizing):值為Auto,實際作用就是取實際控制元件所需的最小值(Setting Height or Width to Auto, which gives child elements the space that they need and no more)。
Proportional sizing(也可以稱之為star sizing因為有個*號表示):
值為*或N*,實際作用就是取儘可能大的值,當某一列或行被定義為*則是儘可能大,當出現多列或行被定義為*則是代表幾者之間按比例方設定尺寸。
下面我們來將上面的知識應用以下看看。
將這三行的值設定為如下數值,結果會是如何:
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="22" />
第0行設為*用來放置ListView,這樣會在實際執行過程中儘可能的充滿整個區域
第1行設為Auto儘量緊湊配列,少佔用空間(如果裡面沒有東西的話,他會小到0,這是你會看不到它)
第2行設為22固定值,只是用來放一個Button使用
對於初學者往往會習慣直接使用控制元件拖拽的形式來將需要的內容新增到窗體上。
會使控制元件在一定的座標上固定位置,這是一種不推薦的做法,在此給大家講解以下WPF中的佈局觀(Layout Philosophy):
在WPF窗體中,一個窗體只能持有一個控制元件,當多個控制元件想要在窗體中展現時,就需要首先設定一個容器控制元件(Container)
然後將其他控制元件放到這個控制元件裡面,形成樹狀結構.
因此,佈局觀第一條就是,控制元件的佈局應該有容器來決定,而不是通過自身使用margin之類的東西來控制位置。
因為這些屬性原本應該是控制自己內部展現或與鄰里之間關係的;
第二條,控制元件應避免明確的定義具體的尺寸,因為顯示器解析度及windows窗體的大小都有可能隨時改變,如果明確的定義尺寸。
當窗體變動後就會出現大面積的空白或是缺失。但為了控制元件功能及效果的展示,應該限定一個可接受的最大及最小尺寸。
通過MinWidth, MinHeight, MaxWidth, MaxHeight屬性可以實現這一點。第三條,不要將介面元素位置設定成與螢幕座標相關.
現在顯示器解析度比較多樣話(800×600、1024×768,我的顯示器是一臺是1400×1050,還有一個是1024×1280豎式的),這樣的做法還是比較有風險的。
第四條,容器應將有效空間共享給其子控制元件,這也是為了不在窗體調整後,遺留出大塊的空餘。
第五條,容器巢狀使用,因為不同的容器,表現效果不同,必要時應結合使用。
接下來在工具箱(Tool Box)中雙擊ListView,一個小框會出現在介面上。
接下來在工具箱(Tool Box)中雙擊WrapPanel,又一個大框會出現在介面上。
再增加一個Button。
這是你會感覺到介面有點亂了,剛才我們在頂層Grid上面畫線到底起什麼作用了(到目前位置還沒有),讓我們來調整一下下面的XAML語句,最終結果如下:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="22" />
</Grid.RowDefinitions>
<ListView Name="listView1" MinWidth="280" >
<ListView.View>
<GridView x:Name="gridView1">
<GridViewColumn Header="ContactID"></GridViewColumn>
<GridViewColumn Header="FirstName"></GridViewColumn>
<GridViewColumn Header="LastName"></GridViewColumn>
<GridViewColumn Header="EmailAddress"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<WrapPanel Grid.Row="1" Orientation="Horizontal"></WrapPanel>
<Button Grid.Row="2" HorizontalAlignment="Right" Click="button1_Click" Name="button1">Refresh</Button>
</Grid>
這裡有幾點又需要解釋以下了:
1)介紹以下容器控制元件Panel,現在介面中有兩個容器型的控制元件一個是Grid跟元素,另一個是WrapPanel。它們都是容器型控制元件,不過表現上有所不同。
Grid顧名思義“網格”,在之前我們已經定義了三行高度分辨是*, Auto, 22,其實還可以功過ColumnDefinition定義多個列,他的子控制元件被放在一個一個實現定義好的小格子裡面,整齊配列。
而WrapPanel則是將各個控制元件按照行或列的順序摞列,當長度或高度不夠是就會自動調整換例或行。
還有一個常用控制元件這裡稍後會用到StackPanel,將控制元件按照行或列來順序排列不會回行。
2)大家應該注意到了在WrapPanel及Button上面的Grid.Row="n",這個就是Attached Properties(不知道怎麼翻譯了,可能叫‘附著屬性’).
用來設定WrapPanel及Button應該在父容器的什麼位置。這是WPF的特性之一,通俗的理解起來就是,別人有的屬性,由於你跟他產生了關係所以你也有了這個屬於他的屬性。
記得FantasiaX‘水之真諦’曾經給我通俗的解釋過這個特性,這裡照搬出來分享給大家:一個小學生,身高、體重是他的自身屬性,而這個小學生由於是N年級的X班的學生.
因此,這個小學生又帶有了一個附加的屬性,N年級X班。在這個例子裡如果學校作為一個Grid容器,N年級X班可以看作一個小格子,小學生是其中的一個例項,那麼,小學生因為安置在這個班級.
因此獲得了這個班級所擁有的這個屬性,當學期末,老師說,這個學生已經升到N+1年級X班時,這個學生以後就跑到另一個小格子裡去上課了。
Attached Properties的XAML用法就是在自己的屬性設定地方直接使用容器的型別名稱.容器屬性名稱(Grid.Row)設定對應的值。
3)大家應該注意到類似與ListView.View及Grid.RowDefinitions用法,這個叫做Complex Properties(應該叫‘複雜屬性’吧).
其實就是元素的某一個屬性由於不能夠簡單的用名值對實現,因此需要單獨標籤話宣告一下。
4)再有就是x:Name="gridView1"這種用法,叫做Markup Extensions(‘標記擴充套件’吧),這個可是一個滿不錯的特性.
由於後面程式碼中要使用到GridView物件,然而GridView物件有沒有Name屬性,如果後臺程式碼想要呼叫他的話就不得不從父容器向下遍歷來找到想要的物件,這樣無疑增加了後臺程式碼與前臺介面之間的耦合度,試想如果那天突然有需求說要把這個物件從這裡移到另一個容器上去.
那麼介面的變動伴隨著的就是後臺程式碼的一起變動,這與檢視/邏輯分離顯然背道而馳,有了Markup Extensions.
我們想定位一個沒有名字屬性的控制元件,直接為擴充套件一個名稱出來,這個可太方便了(當然,Markup Extensions不只是用來副檔名稱的)。
如果希望每個TextBlock和TextBox成為一對出現的話,應該如何呢?
自然是需要一個容器將他們組織起來.
同時,希望他們在一條線上不回行。這就用到了,我們前面說到的一個容器StackPanel。組織後的程式碼如下:
<WrapPanel Grid.Row="1" Orientation="Horizontal">
<StackPanel Orientation="Horizontal" Margin="5,2,5,2">
<TextBlock Name="textBlock_ContactID" Text="ContactID:" />
<TextBox Name="textBox_ContactID" MinWidth="100" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5,2,5,2">
<TextBlock Name="textBlock_FirstName" Text="FirstName:" />
<TextBox Name="textBox_FirstName" MinWidth="100" />