天天看點

WPF:建構應用程式

WPF相關的項目内容包含在App.Xaml和Window1.xaml中,這些檔案中包含了相當重要的Application對象和Window對象。

Window類

  Window是傳統應用程式的主要元素,用來包含應用程式的内容。WPF Window其實隻是一個包裝過的Win32視窗。作業系統無法區分具有WPF内容的視窗和具有Win32内容的視窗間的差别,它會以相同的方式在非用戶端區域進行渲染。

  Window提供了一種對Win32視窗的直接抽象,其中提供了許多簡單的方法和屬性。在完成Window初始化後,可以調用Show來顯示它,調用Hide讓它隐藏,調用Close來完全的關閉它。

  Window通過初始化一個繼承自Window類的對象,再調用Show方法來建立任意數量的視窗。它也可以把這些Window指派為子視窗。 子視窗和其他上級視窗一樣,但它會随着父視窗的關閉而關閉,随着上級視窗的最小化而最小化,這樣的Window叫作非模态對話框。

  把其他視窗變為自己的子視窗的Window,必須把它的子視窗的Owner屬性設定為它的引用,但這必須在父視窗顯示以後方可。它可通過OwnedWindow屬性來枚舉它的子視窗。

  當一個Window變為活動(active)或非活動(inactive)狀态,相應的Activated及Deactived事件就會被觸發。可通過調用Window的Activate方法來強行使一個Window變為活動狀态。

  關閉視窗時會觸發Closing事件。

Application類

  WPF應用程式裡的線程必須跑在單線程單元裡(STA)。許多API必須從目前線程調用,如果是從其他線程調用,WPF會抛出一個異常。

  為了避免使用Show方法後,視窗立即退出,需要讓應用程式不停的從作業系統配置設定消息給視窗,直到它關閉為止。這些消息和Win32應用程式所 基于的消息是一樣的:WM_PAINT、WM_MOUSEMOVE等等。WPF内部必須處理這些資訊才能在Windows上跑起來。在Win32裡,你要 寫一個消息循環來處理進入的消息,并且把它們傳給相應的視窗過程。在WPF裡,最容易實作這個任務的辦法就是使用 System.Windows.Application類。

使用Application.Run

  Application定義了一個叫作Run的方法,用來保持應用程式一直運作,同時配置設定适當的消息。

WPF:建構應用程式
WPF:建構應用程式

  Application定義了StartUri屬性,它提供了另一種顯示應用程式的第一個視窗的方法,可這樣使用:

WPF:建構應用程式
WPF:建構應用程式

WPF應用程式中的Main方法在哪裡?

  在VS中建立一個WPF Window應用程式時,生成的工程中沒有Main方法,但它還是可以運作。事實上,如果嘗試添加Main方法,将會得到一個編譯錯誤。

  從XAML編譯應用程式是一個特殊的案例,因為VS賦予了XAML檔案一個ApplicateionDefinition的Build Action,這會自動生成Main方法。對于Photo Gallery應用程式來說,這個入口點方法可在App.g.cs裡找到:

WPF:建構應用程式
WPF:建構應用程式

  VS隐藏了這個App.g.cs檔案。

如何在WPF應用程式中獲得指令行參數?

  通常情況下,WPF應用程式不允許實作Main方法,有兩種方法可獲得指令行參數:一種是預告定義一個繼承自Application類的 XAML,這樣就可以手動定義一個帶有字元串數組參數的Main方法。另一種方法是在程式的任何地方調用 System.Environment.GetCommandLineArgs,它傳回的字元串數組與Main方法中獲得的字元串數組相同。

Applicateion類的其他用途

  Application類不隻是一個簡單的程式入口點及消息分發器。它包含一些用來管理正常應用程式級别的任務的事件、屬性和方法。你可以重載 繼承自Application類(比如VS生成的App類)的OnEventName方法來處理這些事件,它們包含Startup和Exit、 Activated和Deactivated,甚至還有SessionEnding事件,它是在使用者登出或關機時觸發的事件,并且可以被取消,你可以通過 ReasonSessionEnding枚舉值來了解詳細資訊。

  因為應用程式通常會有多個視窗,Application定義了一個隻讀的Windows集合,供你通路所有開關的Window。初始視窗可以通過MainWindow屬性來通路,它是個可讀寫屬性,你也可以在任何時候指定任何一個視窗為主視窗。

  預設情況下,所有Window被關閉時,Application就退出了(Run方法在這個時候才最終傳回)。但這個行為是可修改的,可設定 ShutdownMode屬性為不同的值一實作。如:可以讓Application在主視窗退出時退出,而不管其他Window當時的狀态。即使所有的 Window都已關閉,你同樣可以讓Application一直運作,直到顯式的調用Shutdown方法才退出。這個行為對于需要在最小化時,把自己放 到Windows通知區域的應用程式非常有用。

  Propertied集合是Application類中一個非常友善的屬性。Properties很像應用程式狀态或者ASP.NET裡的會話 狀态(session state),它是一個用來存儲資料(key/value)的字典,這些資料可以在Window和其他對象之間共享。你隻需把資料存儲在 Properties集合中就可以了。

  應用程式級别的任務通常在Window的代碼中執行,它需要應用程式中不同的Window來獲得對于目前應用程式執行個體的引用。我們可以通過Application.-Current靜态屬性來通路這個實作。如:

  Application.Current.Properties["CurrentPhotoFilename"] = filename;

如何用WPF建立單執行個體應用程式

  傳統的建立單執行個體應用程式的方法仍然适用于WPF程式,如使用一個已命名的互斥量(mutex)。代碼如下:

WPF:建構應用程式
WPF:建構應用程式

  請确認uniqueName不會被其他應用程式使用!通常,在開發時我們會建立一個GUID來作為辨別。

不用Application對象也可以建立應用程式

  不使用Application對象來呈現應用程式是相當容易的,但你需要手動處理消息分發。

  可以使用Win32技術,但WPF同樣也在System.Windows.Threading命名空間定義了一個底層的Dispatcher 類,它不用救助于Win32 API就能分發消息。如,你的Main方法可以在呈現主視窗後調用Dispatcher.Run來代替Application.Run(事實 上,Application.Run内部就是用Dispatcher.Run來實作消息分發功能的)。但這樣的應用程式仍然缺少其他重要的應用程式管理功 能。如,Dispatcher.Run從不傳回,除非你在某處顯式的調用Dispatcher.ExitAllFrames。

多線程應用程式

  标準WPF應用程式包含一個UI線程及一個渲染線程(渲染線程不直接提供給開發者,它在背景運作,并且處理像合成這樣的底層任務)。可以産生單 獨的線程來執行背景工作,但不能從這些線程中直接與UI線程裡任何繼承自DispatcherObject的對象進行通信。WPF提供了簡單的方法,以便 于任何線程可以排程UI線程來運作它們的代碼。DispatcherObject定義了Dispatcher屬性(Dispatcher類型),它包含了 一些Invoke(同步調用)及BeginInvoke(異步調用)的重載。這些方法會讓你傳入一個委托,并在dispatcher相應的UI線程上被調 用。所有Invoke與BeginInvoke重載都需要一個DispatcherPriority枚舉值。Dispatcher-Priority定義 了10種活動優先級。

  你基至可以在任何産生的線程中通過調用Dispatcher.Run,來為你的應用程式提供多個UI線程。如果你的應用程式有多個頂層Window的話,可以使每個Window運作在一個獨立的線程中。

建立并顯示對話框

  Windows提供了一些正常對話框(模态子視窗)。

正常對話框

  WPF為正常對話框提供了一些内建的類,這些類通過一些屬性和方法提供正常對話框的功能。注意,WPF本身不渲染這些對話框,它是通過内部調用Win32 API來呈現對話框并與它們通信的。

  使用内建對話框的步驟大約為:初始化對話框,調用它的ShowDialog方法,然後處理它的結果。

自定義對話框

  在WPF中,建立使用對話框與建立使用視窗基本相同。事實上,對話框就是視窗,但通常要額外處理傳回的對話框結果。

  調用ShowDialog方法顯示模态視窗,調用Show方法則顯示非模态視窗。ShowDialog是阻塞式調用,并且它傳回一個可以為null的Boolean(C#中的bool?類型)。

ShowDialog的另一種用法

  要在允許消息分發的同時獲得對話框的阻塞行為,Window的ShowDialog方法會像Application.Run那樣調用Dispatcher.Run。是以以下方法可以在不使用Application類的情況下啟動WPF Window:

維持并恢複應用程式狀态

  一個标準的Windows應用程式可以擁有對目前計算機的所有通路權限,是以有許多不同的存儲資料的方式,如果使用系統資料庫或本地檔案系統。但另 一種充滿魅力的方法是使用.NET Framework的分離存儲技術。除了使用簡單以外,它适用于所有能運作托管代碼的環境。