使用VS2010為Windows7編寫(xiě)一個(gè)殺手級(jí)WPF應(yīng)用
原創(chuàng)【51CTO經(jīng)典譯文】當(dāng)你使用***的操作系統(tǒng),在***的框架上構(gòu)建應(yīng)用程序,并且使用***版本的Visual Studio的時(shí)候,你可以使用許多令人興奮的新特性。你可以學(xué)習(xí)一下怎樣使用Visual Studio 2010, WPF 4 和 the Windows API Code Pack給你的應(yīng)用程序添加Windows 7 UI。
Windows 7 UI有很多令人興奮的元素,例如:全新的任務(wù)欄,或者跳轉(zhuǎn)列表,視覺(jué)體驗(yàn)本身并不屬于應(yīng)用程序的范疇,但是它是應(yīng)用程序體驗(yàn)的重要組成部分。作為一個(gè)WPF開(kāi)發(fā)者,你可以把那些元素添加到你的Windows7應(yīng)用程序中,隨心所欲地定制它們?cè)谥鞔翱趦?nèi)部和外部的行為。
使用WPF4,你幾乎可以訪問(wèn)所有的Windows 7 UI特性。WPF4內(nèi)置了對(duì)Windows7任務(wù)欄的支持,其中包括可以自定義的縮略圖預(yù)覽,通過(guò)進(jìn)度條和“圖標(biāo)覆蓋”(icon overlay)從任務(wù)欄獲得視覺(jué)反饋,以及可以自定義的跳轉(zhuǎn)列表。雖然這些特性最終是通過(guò)Windows 7的原生API來(lái)提供的,但是WPF用托管的代碼對(duì)它們進(jìn)行了封裝,通過(guò)WPF類(lèi)的形式把它們暴露出來(lái)。這意味著你可以在XAML中創(chuàng)建跳轉(zhuǎn)列表對(duì)象和其他的UI對(duì)象,并且可以通過(guò)許多依賴(lài)屬性(dependency property)來(lái)綁定它們。
Visual Studio 2010本身就包含許多和WPF有關(guān)的新特性,其中包括一個(gè)全新的可視化設(shè)計(jì)器,拖放式的數(shù)據(jù)綁定,以及在XAML中的標(biāo)記擴(kuò)展的智能感知。這些特性已經(jīng)和WPF的任務(wù)欄類(lèi)整合到一起了,它們可以讓你充分地利用Visual Studio的***版本的全部功能,來(lái)構(gòu)建時(shí)尚的Windows7應(yīng)用程序。
雖然WPF4對(duì)任務(wù)欄有很好的支持,但是,還有一些其他方面的Windows 7 API它并沒(méi)有封裝。例如:Windows7樣式的通用對(duì)話(huà)框。你只能使用Windows API Code Pack和一個(gè)外部的托管封裝庫(kù)在WPF中訪問(wèn)這些API。Windows API Code Pack有它自己的一套shell和任務(wù)欄類(lèi),在WPF 3.5 SP1中也可以使用它們。
(Windows API Code Pack的下載地址:http://code.msdn.microsoft.com/WindowsAPICodePack)
數(shù)據(jù)綁定和Visual Studio 2010的WPF設(shè)計(jì)器
在接觸Windows7的新特性以前,讓我們先來(lái)看一看在全新的Visual Studio 2010的WPF設(shè)計(jì)器中的一個(gè)基礎(chǔ)的數(shù)據(jù)驅(qū)動(dòng)的WPF應(yīng)用程序。在Visual Studio 2010中,你可以在設(shè)計(jì)的時(shí)候通過(guò)把數(shù)據(jù)源拖放到可視化的設(shè)計(jì)器中的方式來(lái)創(chuàng)建數(shù)據(jù)綁定。
如果你把一個(gè)數(shù)據(jù)源項(xiàng)拖放到一個(gè)現(xiàn)有的控件上(例如,把一個(gè)文本字段拖放到一個(gè)文本框中),那么設(shè)計(jì)器會(huì)為那個(gè)數(shù)據(jù)源創(chuàng)建一個(gè)窗口資源,然后把這個(gè)字段綁定到那個(gè)控件上。如果你把一個(gè)數(shù)據(jù)源項(xiàng)拖放到一個(gè)容器上,那么設(shè)計(jì)器會(huì)創(chuàng)建一個(gè)相應(yīng)的綁定控件,然后把這個(gè)控件添加到那個(gè)容器中。如果默認(rèn)的類(lèi)型并不合適,你可以自己設(shè)置這個(gè)綁定控件的類(lèi)型。在截圖1中,我把一個(gè)來(lái)自于AdventureWorks 2008樣例數(shù)據(jù)庫(kù)的數(shù)據(jù)表拖放到一個(gè)窗口中,設(shè)計(jì)器自動(dòng)地創(chuàng)建了一個(gè)數(shù)據(jù)網(wǎng)格控件。當(dāng)我們開(kāi)發(fā)在Windows7任務(wù)欄上顯示進(jìn)度的功能的時(shí)候,我們將會(huì)用到這個(gè)數(shù)據(jù)網(wǎng)格。
(截圖1:把一個(gè)表數(shù)據(jù)源拖放到主窗口上,會(huì)生成了一個(gè)數(shù)據(jù)網(wǎng)格控件)
除了基礎(chǔ)的創(chuàng)建之外,我們還做了一點(diǎn)額外的工作,我們使用漸變式的畫(huà)刷來(lái)設(shè)置窗口的背景。Visual Studio 2010內(nèi)置了一個(gè)可視化的畫(huà)刷編輯器,這讓創(chuàng)建和使用漸變式的畫(huà)刷,圖像畫(huà)刷,以及純色的畫(huà)刷變得更加容易了。在一個(gè)畫(huà)刷屬性的屬性編輯器上下拉可以直接在編輯器中看到反饋,這可以讓你以可視化的方式創(chuàng)建漸變式的畫(huà)刷,或者為一個(gè)圖像畫(huà)刷選擇一個(gè)圖像。
(截圖2:使用可視化的畫(huà)刷編輯器創(chuàng)建一個(gè)背景畫(huà)刷。)
和Windows7的任務(wù)欄進(jìn)行交互
在Windows7中,你可以通過(guò)一個(gè)橫跨任務(wù)項(xiàng)背景的進(jìn)度條,在任務(wù)欄上顯示需要長(zhǎng)時(shí)間才能完成的操作的進(jìn)度。Internet Explorer使用任務(wù)欄進(jìn)度條來(lái)跟蹤文件的下載情況就是一個(gè)很好的例子。
你可以通過(guò)TaskbarItemInfo類(lèi)和Windows7的任務(wù)欄進(jìn)行交互,在主窗口上,這個(gè)類(lèi)是通過(guò)一個(gè)依賴(lài)屬性暴露出來(lái)的。你可以在XAML中創(chuàng)建一個(gè)TaskbarItemInfo對(duì)象:
- <Window.TaskbarItemInfo>
- <TaskbarItemInfo x:Name="TaskbarItemInfo1" Description="Customer Browser: Using WPF 4 on Windows 7”>
- </TaskbarItemInfo>
- </Window.TaskbarItemInfo>
你可以直接在XAML中編輯TaskbarItemInfo的屬性,也可以通過(guò)Visual Studio的屬性編輯器來(lái)編輯TaskbarItemInfo的屬性。這個(gè)XAML代碼片段只展示了名字和Description屬性,這個(gè)屬性用來(lái)指定在任務(wù)欄上顯示的提示文本。大多數(shù)的任務(wù)欄特性都可以通過(guò)這個(gè)類(lèi)來(lái)訪問(wèn)。
為了顯示進(jìn)度條,你只需設(shè)置其中兩個(gè)屬性就可以了,這兩個(gè)屬性分別是:ProgressValue 和 ProgressState。ProgressState的默認(rèn)值是None;你可以把它設(shè)置成Indeterminate來(lái)顯示一個(gè)滾動(dòng)樣式的進(jìn)度條,或者也可以把它設(shè)置成Normal,實(shí)際上我們就是這樣設(shè)置的,這樣可以顯示一個(gè)標(biāo)準(zhǔn)的進(jìn)度條:
- TaskBarItemInfo1.ProgressValue = 0;
- TaskBarItemInfo1.ProgressState = TaskbarItemProgressState.Normal;
把ProgressValue設(shè)置成1.0會(huì)顯示一個(gè)處于完成狀態(tài)的進(jìn)度條。為了跟蹤數(shù)據(jù)表的填充情況,我們首先會(huì)執(zhí)行一個(gè)計(jì)數(shù)查詢(xún),計(jì)算出這個(gè)數(shù)據(jù)表的總行數(shù),把這個(gè)數(shù)值作為完成狀態(tài)的進(jìn)度值。然后,我們可以訂閱這個(gè)數(shù)據(jù)表的RowChanged,添加下面這兩行代碼來(lái)更新任務(wù)欄上的進(jìn)度條:
this.rowsUpdated++;
TaskbarItemInfo1.ProgressValue =((double)this.rowsUpdated)/this.rowCount; //將this.rowsUpdated顯式轉(zhuǎn)換為double類(lèi)型,防止計(jì)算的過(guò)程中發(fā)生精度丟失。
除了進(jìn)度條,你還可以使用“圖標(biāo)覆蓋”(icon overlay)來(lái)提供和應(yīng)用程序狀態(tài)有關(guān)的反饋。一個(gè)“圖標(biāo)覆蓋”是一個(gè)小的圖像,在任務(wù)欄中,它位于主應(yīng)用程序圖標(biāo)的前面。我們將會(huì)使用一個(gè)“圖標(biāo)覆蓋”來(lái)顯示我們的客戶(hù)列表的過(guò)濾器設(shè)置。
截圖3展示了一個(gè)在任務(wù)欄上使用“圖標(biāo)覆蓋”的樣例應(yīng)用程序。在主應(yīng)用程序中,你可以通過(guò)在一個(gè)組合框中選擇一個(gè)國(guó)家的方式,按照國(guó)家來(lái)查看客戶(hù)。如果對(duì)過(guò)濾器進(jìn)行了設(shè)置,任務(wù)欄圖標(biāo)會(huì)顯示一個(gè)小的圖像,這個(gè)小圖像是在過(guò)濾器中選擇的那個(gè)國(guó)家的國(guó)旗,它就是一個(gè)“圖標(biāo)覆蓋”。
(截圖3:通過(guò)一個(gè)“圖標(biāo)覆蓋”來(lái)顯示過(guò)濾器設(shè)置的Customer Browser應(yīng)用程序。)
你可以通過(guò)給TaskbarItemInfo的Overlay屬性指定圖像源的方式來(lái)設(shè)置一個(gè)“圖標(biāo)覆蓋”。對(duì)于這個(gè)例子來(lái)說(shuō),我針對(duì)每個(gè)國(guó)旗圖像創(chuàng)建了一個(gè)位圖資源。然后,當(dāng)對(duì)過(guò)濾器進(jìn)行設(shè)置的時(shí)候,我們可以從窗口資源載入圖像,設(shè)置一個(gè)“圖標(biāo)覆蓋”:
- string resourceKey = “flag_” + countryName;
- TaskbarItemInfo1.Overlay =(ImageSource)this.TryFindResource(resourceKey);
自定義縮略圖
當(dāng)你的應(yīng)用程序運(yùn)行在Windows7上的時(shí)候,應(yīng)用程序縮略圖預(yù)覽是你可以免費(fèi)獲得的UI perk之一。Windows 7可以通過(guò)在任務(wù)欄上彈出一個(gè)小窗口的方式來(lái)顯示主應(yīng)用程序窗口的縮略圖。用戶(hù)可以使用縮略圖預(yù)覽來(lái)激活或關(guān)閉這個(gè)應(yīng)用程序,或者在應(yīng)用程序?qū)嵗g進(jìn)行選擇。
通過(guò)TaskbarItemInfo的ThumbnailClipMargin屬性,你可以很容易地對(duì)你的應(yīng)用程序的縮略圖進(jìn)行定制。使用這個(gè)屬性,你可以在主窗口內(nèi)指定一個(gè)矩形(這個(gè)矩形的內(nèi)容會(huì)顯示在縮略圖中),而不是顯示整個(gè)主窗口。
ThumbnailClipMargin是一個(gè)依賴(lài)屬性(dependency property),所以,除了指定一個(gè)靜態(tài)的邊框之外,你還可以把它綁定到另外一個(gè)控件的邊框上,使用那個(gè)控件作為應(yīng)用程序預(yù)覽。通過(guò)這種方法,我把縮略圖預(yù)覽設(shè)置成只顯示客戶(hù)的數(shù)據(jù)網(wǎng)格。與其看另外一個(gè)代碼片段,到不如看一看Visual Studio中的情況。
(截圖4:設(shè)置ThumbnailClipMargin綁定。)
截圖4展示了在XAML中設(shè)置綁定,它還展示了Visual Studio提供的全新的標(biāo)記擴(kuò)展的智能感知。我們必須把綁定Path設(shè)置成“Margin”,我們可以在選項(xiàng)列表中選擇Path。
縮略圖預(yù)覽還可以包含一組工具欄按鈕,讓用戶(hù)通過(guò)預(yù)覽窗口直接給應(yīng)用程序發(fā)送命令。有時(shí)這些特性會(huì)比較有用,例如,發(fā)送媒體命令(例如:播放或暫停)的時(shí)候。對(duì)于這個(gè)例子來(lái)說(shuō),我創(chuàng)建了一個(gè)“Copy”工具欄按鈕,從一個(gè)TextBox拷貝客戶(hù)的電子郵件地址。
TaskbarItemInfo包含一個(gè)叫作“ThumbButonInfos”的集合屬性,通過(guò)這個(gè)屬性,你可以創(chuàng)建一個(gè)縮略圖工具欄。Visual Studio 2010也完全支持這個(gè)特性,你可以在集合編輯器中編輯每個(gè)按鈕項(xiàng),或者,你也可以直接在XAML中完成這個(gè)工作。
一個(gè)ThumbButonInfo的XAML通常會(huì)指定要發(fā)送的命令,命令的目標(biāo),這個(gè)按鈕要使用的圖像,以及工具提示文本。這是我們的“Copy”按鈕的XAML代碼:
- <ThumbButtonInfo Command="ApplicationCommands.Copy"
- Description="Copy E-Mail Address"
- ImageSource="/wpf4example;component/Images/copy.png"
- CommandTarget="{Binding ElementName=textBox1}" />
通過(guò)WPF命令的“魔力”,這個(gè)按鈕會(huì)根據(jù)是否在文本框中選擇了文本而自動(dòng)地啟用或禁用。
(截圖5:自定義縮略圖圖像(只顯示DataGrid)和“Copy”工具欄按鈕)
跳轉(zhuǎn)列表
跳轉(zhuǎn)列表是常用的任務(wù)或與一個(gè)應(yīng)用程序相關(guān)的文件的列表,右鍵單擊任務(wù)欄圖標(biāo),它就會(huì)彈出來(lái),或者,在開(kāi)始菜單的應(yīng)用程序項(xiàng)上,它也會(huì)彈出來(lái)。你可以通過(guò)添加文件,任務(wù),或者你自己的任務(wù)分類(lèi)的方式來(lái)對(duì)你的應(yīng)用程序的跳轉(zhuǎn)列表進(jìn)行定制。
跳轉(zhuǎn)列表是和應(yīng)用程序本身相關(guān)聯(lián)的,而不是和具體的應(yīng)用程序?qū)嵗嚓P(guān)聯(lián)。你可以使用程序代碼,在你的應(yīng)用程序中添加一個(gè)自定義的跳轉(zhuǎn)列表,或者,你也可以在XAML中(在app.xaml文件中)把一個(gè)跳轉(zhuǎn)列表掛載到一個(gè)應(yīng)用程序?qū)ο笊稀?/p>
- <JumpList.JumpList>
- <JumpList ShowRecentCategory="True”
- ShowFrequentCategory="True">
- <JumpTask Title="Notepad”
- Description="Run Notepad"
- ApplicationPath="c:\windows\notepad.exe"
- IconResourcePath="c:\windows\notepad.exe"/>
- </JumpList>
- </JumpList.JumpList>
如果你在XAML中創(chuàng)建了一個(gè)跳轉(zhuǎn)列表,在這個(gè)應(yīng)用程序初始化以后,這會(huì)自動(dòng)地應(yīng)用到Windows Shell中。
跳轉(zhuǎn)列表可以包含跳轉(zhuǎn)任務(wù)(就像在這個(gè)XAML代碼片段中展示的那樣),來(lái)啟動(dòng)其他的程序,或者,它們也可以包含跳轉(zhuǎn)路徑,直接鏈接到文件。如果你的應(yīng)用程序注冊(cè)為某種文件類(lèi)型的處理程序,那么這些跳轉(zhuǎn)路徑只能顯示在你的跳轉(zhuǎn)列表上。
Windows Shell為每個(gè)應(yīng)用程序維護(hù)了一個(gè)最近頻繁使用的文件的列表。你可以設(shè)置ShowRecentCategory 和 ShowFrequentCategory屬性,在應(yīng)用程序的跳轉(zhuǎn)列表中顯示這些列表。
除了這些標(biāo)準(zhǔn)的分類(lèi)外,你還可以創(chuàng)建自定義的分類(lèi)。下面這段代碼添加了一個(gè)鏈接到calc.exe的跳轉(zhuǎn)任務(wù),然后把它放到一個(gè)自定義的分類(lèi)中。
- JumpTask jumpTask1 = new JumpTask();
- jumpTask1.ApplicationPath =
- "C:\\windows\\system32\\calc.exe";
- jumpTask1.IconResourcePath =
- "C:\\windows\\system32\\calc.exe";
- jumpTask1.Title = "Calculator";
- jumpTask1.CustomCategory = "Calculation";
- JumpList jumpList1 = JumpList.GetJumpList(App.Current);
- jumpList1.JumpItems.Add(jumpTask1);
- jumpList1.Apply();
(截圖6:一個(gè)帶有標(biāo)準(zhǔn)分類(lèi)和一個(gè)自定義分類(lèi)的跳轉(zhuǎn)列表)
Windows7的對(duì)話(huà)框和控件
WPF并沒(méi)有封裝Windows7的通用文件對(duì)話(huà)框API。要使用這些API,你可以求助于Windows API Code Pack。這個(gè)代碼包可以讓你從WPF應(yīng)用程序中啟動(dòng)一些“了解”Windows 7的Shell特性(例如已知的文件夾和庫(kù))的,通用的對(duì)話(huà)框。
要使用這個(gè)代碼包,需要?jiǎng)?chuàng)建一個(gè)代碼包解決方案,然后把代碼包程序集的引用添加到你的應(yīng)用程序中。這樣的話(huà),你就可以使用代碼包命名空間中的類(lèi)了,包括CommonDialog。
Windows7有一系列已知的文件夾(例如:Desktop, Pictures Library),在CommonDialog中,你可以直接指定這些文件夾,無(wú)需指定具體的文件路徑。這段代碼把打開(kāi)文件對(duì)話(huà)框的初始路徑設(shè)置成了Pictures Library。
- CommonOpenFileDialog dlg = new CommonOpenFileDialog();
- dlg.InitialDirectoryShellContainer = (ShellContainer)KnownFolders.PicturesLibrary;
你可以使用已知的文件夾(或者,更普遍點(diǎn)來(lái)說(shuō),你可以使用Shell對(duì)象)來(lái)指定通用的打開(kāi)文件對(duì)話(huà)框或保存文件對(duì)話(huà)框的一些設(shè)置。例如,這行代碼給這個(gè)打開(kāi)文件對(duì)話(huà)框添加了一個(gè)新的打開(kāi)路徑:Video Library
- dlg.AddPlace((ShellContainer)KnownFolders.VideosLibrary,FileDialog.AddPlaceLocation.Bottom);
(截圖7:一個(gè)帶有自定義的打開(kāi)路徑的Windows7打開(kāi)文件對(duì)話(huà)框)
Windows API Code Pack還提供了一個(gè)用WPF封裝的ExplorerBrowser控件,通過(guò)它,你可以在一個(gè)Windows7樣式的資源管理器界面中顯示文件和其他的Shell對(duì)象。要使用這個(gè)控件,你需要做的所有事情就是在XAML中聲明它:
- <WindowsAPICodePackPresentation:ExplorerBrowser x:Name=”explorerBrowser1”/>
然后,在這個(gè)基礎(chǔ)控件上調(diào)用Navigate方法,在你的窗口中顯示選定的文件夾:
- explorerBrowser1.ExplorerBrowserControl.Navigate((ShelObject)KnownFolders.SampleMusic);
(插圖8:Windows API code pack中的ExplorerBrowser控件,它運(yùn)行在一個(gè)樣例應(yīng)用程序窗口中。)
新的工具支持新的UI
在WPF4,Windows API code pack,和完整的Visual Studio 2010 UI的幫助下,你可以把最酷的,原生的Windows7特性發(fā)揮得***,而且根本不用離開(kāi)托管代碼。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),這是一次重大的勝利,希望這可以提升他們的應(yīng)用程序的Windows7用戶(hù)體驗(yàn)。
原文標(biāo)題:Using Visual Studio 2010 to Write Killer WPF Apps for Windows 7
【編輯推薦】