麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

用WPF構建強大的用戶體驗

2019-11-17 04:37:01
字體:
來源:轉載
供稿:網友

  用戶體驗是內容(content)和內容寄宿(host)方式的綜合結果。在Windows PResentation Foundation中,內容是用標準控件、2D和3D圖像、動畫、數據綁定、布局、樣式和
  Windows Presentation Foundation應用程序模型有兩種應用程序類型:標準的和瀏覽器的。標準應用程序通過自己的窗體、對話框和消息框顯示內容,而瀏覽器應用程序由寄宿在瀏覽器中的頁面組成。

  類似地,Windows Presentation Foundation也包含兩種導航模式:菜單驅動的和超鏈接驅動的。菜單驅動的應用程序答應用戶使用菜單條、工具條、窗體和對話框導航到某些內容和功能。超鏈接驅動的應用程序使用超鏈接來傳遞導航體驗,與Web應用程序類似。

  很明顯,標準的應用程序自然地支持菜單驅動導航,而瀏覽器應用程序自然地支持超鏈接導航。但是Windows Presentation Foundation應用程序模型能夠讓兩者混合。在大多數情況下,它可以把超鏈接驅動的體驗部分地或者全部地集成到標準應用程序中。這種基于用戶體驗類型的合并會使用戶受益。一旦你決定了自己希望提供的用戶體驗,就可以使用Windows Presentation Foundation模型來建立應用程序了。

  應用程序的類型

  我們來看看示例Box應用程序,如圖1所示。這是一個標準的、菜單驅動的應用程序,答應用戶根據需求列舉、排序、查看和刪除盒子訂單。為了提供這種用戶體驗,你必須從應用程序模型積木結構的基礎開始:建立一個應用程序。

用WPF構建強大的用戶體驗(圖一)
圖1:Box應用程序

  基于Windows的應用程序由一些標準的管線(plumbing)組成,包括一個入口點和一個消息循環,也可能需要下面的通用應用程序服務中一個或多個:

  · 處理命令行參數

  · 返回退出代碼

  · 應用程序范圍的狀態信息

  · 檢測和響應未處理的異常

  · 治理應用程序的生命周期

  Windows Presentation Foundation把管線和服務集中在一個類型(System.Windows.
application)中了,你可以在標記(XAML)、代碼(C#或 Visual Basic)、或者兩者組合(標記和后臺代碼)中使用它。Application類型變得如此重要,以至于Visual Studio 2005會自動地向每個新的.NET Framework 3.0(以前的WinFX)窗體應用程序項目添加該類型的一個實例:

<!--App.xaml (markup)-->
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BoxApplicationWindow.App"
/>

// App.xaml.cs (后臺代碼)
public partial class App : Application { ... }
  假如你使用以前的Windows顯示技術編寫過程序(例如Windows窗體和Win32),你可能會很驚奇。這兒根本就沒有一段代碼與建立標準的基于Windows的應用程序管道(包括入口點)的代碼相似。這是因為Visual Studio 2005已經為你建立了應用程序管道,它是在配置應用程序標記文件的"應用程序定義"構建操作(build action)的時候完成這項工作的,如圖2所示。

用WPF構建強大的用戶體驗(圖二)
圖2:設置應用程序的XAML文件

  在后臺,它生成的代碼與下面的類似:

// App.cs
using System;

public partial class App : Application
{
 [STAThread]
 public static void Main()
 {
  // 初始化和運行應用程序
  App application = new App();
  application.Run();
 }
}
  Visual Studio 2005到底創建了什么內容都是無關緊要的,因為你既不需要編寫也不需要理解它的復雜性。作為代替的是,到此為止,你被微軟顯示技術中的大多數應用程序抽象給隔離了,你可以使用它和少量標記來建立一個可運行的應用程序。你所需要做的只是使用Application的服務。對于獨立的應用程序來說,這包括在應用程序開始運行時顯示一個窗體。窗體(Window)

  在Windows Presentation Foundation中,窗體就是Window。通常情況下,在標準的應用程序中,窗體是寄宿內容的核心單位。在Visual Studio 2005中你可以選擇"項目 添加新項 WinFX Window"給項目增加一個窗體定義,它會產生下面的內容:

<!--MainWindow.xaml (markup)-->

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BoxApplication.MainWindow"
</Window>

// MainWindow.xaml.cs (codebehind)
using System.Windows;
public partial class MainWindow : Window { ... }
  在添加窗體定義之后,Visual Studio 2005自動地把標記文件的"構建類型"設置為Page(頁面)。在構建的時候,該標記被轉換為一種特定的資源類型,可以被統一的資源標識符(URI)唯一地識別出來。從本質上說,這使得Windows Presentation Foundation可以使用URI宣告式地載入一個窗體,你可以使用這種能力來指定一個應用程序啟動時自動打開的窗體。要達到這個目的,只需要設置標記中的Application.StartupUri屬性,如下所示:

<!--App.xaml (markup)-->
<Application ... StartupUri="MainWindow.xaml" />
  上面的代碼建立和顯示了一個如圖3所示的窗體。與所有其它窗體類似,Windows Presentation Foundation窗體包含客戶端區域(它里面放置Windows Presentation Foundation內容和控件)和非客戶端區域(邊框、標題條、以及一些與此相關的修飾部分)。

用WPF構建強大的用戶體驗(圖三)
圖3:窗體和它的各部分

  Application.StartupUri指定的窗體是非模態的,這意味著它不會阻止用戶使用應用程序中的其它窗體。假如你需要顯示其它的非模態窗體,你只需要調用Window.Show:

// MainWindow.xaml.cs (codebehind)
public partial class MainWindow : Window
{
 void helpContentsMenuItem_Click(object sender, RoutedEventArgs e)
 {
  HelpWindow window = new HelpWindow();
  window.Owner = this; // 確保窗體總是顯示在本窗體之上
  window.Show();
 }
 ...
}
  Windows Presentation Foundation也支持顯示模式窗體,即阻止用戶使用應用程序中其它窗體的窗體。典型情況下(不是一定的),模式窗體一般被當作對話框使用,用來收集完成某項事務(例如創建訂單)所需要的數據。在Windows Presentation Foundation中顯示模式窗體,需要調用Window.ShowDialog(如下代碼所示)。

  代碼:調用Window.ShowDialog

// MainWindow.xaml.cs (codebehind)
public partial class MainWindow : Window
{
 void CreateOrder()
 {
  OrderABoxDialog dlg = new OrderABoxDialog();
  dlg.Owner = this; // 確保對話框一直處于本窗體之上
  bool dialogResult = dlg.ShowDialog();

  // 假如訂單的細節信息都是爭取的,就向訂單列表添加訂單
  if (dialogResult == true)
  {
   this.orders.Add(dlg.Order);
  }
 }
 ...
}
  Window類也支持典型的對話框行為,答應用戶接受或終止一個對話框,并且可以把用戶的選擇返回給調用代碼以供處理。

  消息框是一種非凡的、給用戶顯示信息或者詢問用戶的對話框,Windows Presentation Foundation的MessageBox類型支持它:

// MainWindow.xaml.cs (codebehind)
public partial class MainWindow : Window
{
 void aboutMenuItem_Click(object sender, RoutedEventArgs e)
 {
  MessageBox.Show("Box Application, Version 1.0");
 }
 ...
}
  消息框、對話框、窗體和應用程序窗體是標準的、菜單驅動的應用程序開發模型的核心。在很久以前的顯示技術中也都支持這些內容。但是,Windows Presentation Foundatio通過對超鏈接驅動的導航支持擴展了這些內容,它從導航內容的基本單位--頁面開始。Page類

  Page是一種與Html Web頁面(它使Web更加普及了)類似的Windows Presentation Foundation內容。前面我提到過,Windows Presentation Foundation在標準的和瀏覽器應用程序中都支持超鏈接驅動的導航。Windows Presentation Foundation中的超鏈接驅動的導航體驗的內容基礎是Page(頁面)。

  在Visual Studio 2005中,通過選擇"項目 添加新文件 WinFX 頁面"給項目添加標記和后臺頁面定義。它生成的代碼與圖5所示的相似。

  代碼:添加標記和后臺頁面定義

<!--HomePage.xaml (markup)-->

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BoxApplicationNavigationWindow.HomePage" ... >
...
<!--Order Content-->
...
</Page>

// HomePage.xaml.cs (codebehind)
using System.Windows.Controls; // Page
public partial class HomePage : Page { ... }
  頁面標記文件是在頁面構建項中配置的。假如使用窗體,可以從URI載入它,這意味著配置Application.StartupUri之后可以在應用程序啟動時自動地載入頁面:

<!--App.xaml (markup)-->
<Application ... StartupUri="HomePage.xaml" />
  由于Page類不是窗體,也不是衍生自Window的,因此它不能寄宿自身。幸運的是,Application類足夠智能,當StartupUri被設置為特定頁面的時候,它可以檢測到。Application會建立一個窗體,在窗體內寄宿該頁面。

  Hyperlink類

  所有的超鏈接驅動的應用程序都擁有多個XAML頁面,你必須為用戶提供一條在頁面之間進行導航的途徑。你可能猜到了Windows Presentation Foundation是用超鏈接來實現超鏈接驅動的導航的。你可以采用下面的方式給頁面增加超鏈接:

<!--HomePage.xaml (markup)-->
<Page ... >
...
<Hyperlink NavigateUri= "OrderingGuidelinesPage.xaml">
Ordering Guidelines
</Hyperlink>
...
</Page>
  上面的代碼配置超鏈接以導航到一個XAML頁面,它使用的基本編程模型與HTML HREF是一樣的。你指定一個要導航到的URI(例子中是OrderingGuidelinesPage.xaml)和文本,用戶可以看到文本并點擊它來發起導航。

  由于太多的可瀏覽內容都存在于基于HTML的Web頁面上,因而Windows Presentation Foundation和超鏈接能夠讓你無縫地導航到基于Web的內容。例如,"訂單向導"已經存在于BOX應用程序的Web站點上,因此,我們不應該把它們復制成應用程序中的XAML文件,而只需要簡單地改變NavigateUri屬性的值,如下所示:

<!--HomePage.xaml (markup)-->
<Page ... >
...
<Hyperlink NavigateUri="OrderingGuidelinesPage.html">
Ordering Guidelines
</Hyperlink>
...
</Page>導航窗體(NavigationWindow)

  現在你可能對幾個問題很迷惑。由于頁面不是窗體,那么寄宿頁面的窗體來自哪兒?當我們點擊超鏈接的時候,到底是什么在處理導航?HTML Web頁面內容是如何顯示在Windows Presentation Foundation應用程序中的?所有的這些都是由NavigationWindow來處理的。

  當你把Application.StartupUri設置為XAML或HTML頁面的時候,應用程序(我們知道這些頁面都不會提供自己的窗口)建立一個NavigationWindow實例來寄宿它們。

  NavigationWindow衍生自Window,并擴展了它的可視化外表,使它的樣子與瀏覽器類似,如圖6所示。

用WPF構建強大的用戶體驗(圖四)
圖6:NavigationWindow

  當用戶點擊XAML頁面上的超鏈接的時候,超鏈接要求NavigationWindow導航到特定的URI。NavigationWindow就載入URI所指向的頁面,從而實現寄宿它。被載入頁面的URI位置會存儲在NavigationWindow.Source屬性中,被載入頁面的內容在NavigationWindow.Content屬性中。

  當內容發生改變的時候,就進行導航,并且把之前的內容添加到導航歷史中。這個過程也是由NavigationWindow治理的。導航UI為導航操作提供了兩個按鈕和一個下拉列表。請注重,你不僅僅可以使用NavigationWindow的默認樣式,使用Windows Presentation Foundation支持的多種樣子,你還可以輕易地建立自己的導航UI。

  到目前為止,我為你介紹了如何使用標記來配置需要導航的超鏈接URI。但是,有時候你無法宣告式地決定導航。例如,假如希望查看訂單,你就必須建立一個頁面實例,并把自己希望查看的訂單傳遞給它。這是無法宣告式地完成的。作為代替,你必須使用代碼,如圖7所示。

  圖7:用代碼導航

HomePage.xaml (markup)
<Page ... >
...
<Hyperlink Click="viewHyperlink_Click">
View
</Hyperlink>
...
</Page>

HomePage.xaml.cs (codebehind)
public partial class HomePage : Page
{
 void viewHyperlink_Click(object sender, RoutedEventArgs e)
 {

  // 查看訂單
  VieWorderPage page = new ViewOrderPage(GetSelectedOrder());
  NavigationWindow window = (NavigationWindow)this.Parent; // Don't do this!
  window.Navigate(page);
 }

 Order GetSelectedOrder()
 {
  return (Order)this.ordersListBox.SelectedItem;
 }
 ...
}
  當超鏈接被點擊的時候,它的Click事件處理程序獲取當前選中的訂單,在實例化的過程中把它傳遞給ViewOrderPage,并調用它的宿主NavigationWindow的Navigate方法,接著它把頁面作為對象而不是URI進行導航。

  你可能發現獲取宿主NavigationWindow的引用有些古怪。這是必然的,因為頁面沒有任何可用于了解自己所寄宿的內容的外部信息。頁面可以使用自己的Parent屬性來檢測宿主,但是Parent返回的是DependencyObject引用,而不是特定宿主類型的強類型(strongly typed)引用。因此,把Parent轉換為特定的類型意味著頁面知道誰可以寄宿它。但是,你會發現頁面可以擁有多種宿主類型。因此,假如你打算讓多種宿主類型寄宿自己的頁面,你就需要一個與宿主無關的編程執行導航的方法。

  導航服務(NavigationService)

  在Windows Presentation Foundation中,頁面和頁面宿主之間的分離是由NavigationService實現的,它實現了導航引擎的基本功能,包括導航、導航歷史、導航生命周期、內容、為部分內容查找導航服務。如下代碼顯示了NavigationService類型的基本成員。NavigationWindow并沒有真正地實現自己的導航引擎;它是用自己的NavigationService實例來實現的。

  代碼:NavigationService類型的基本成員

sealed class NavigationService : IContentContainer
{
 // 導航
 public bool Navigate(Uri source); // 導航到URI
 public void Refresh(); // 重新導航到當前內容
 public void StopLoading(); // 停止當前的導航 // 導航歷史
 public bool CanGoBack { get; } // Content in back nav. history?
 public bool CanGoForward { get; } // Content in forward nav. history?
 public void GoBack(); // Go to previous content in nav. history
 public void GoForward(); // Go to next content in nav. history

 // 導航的生命周期
 // 導航請求
 public event NavigatingCancelEventHandler Navigating;
 // 導航到內容
 public event NavigatedEventHandler Navigated;
 // 內容載入了
 public event LoadCompletedEventHandler LoadCompleted;
 // 導航錯誤
 public event NavigationFailedEventHandler NavigationFailed;
 // 下載的字節數
 public event NavigationProgressEventHandler NavigationProgress;
 // 導航停止了
 public event NavigationStoppedEventHandler NavigationStopped;

 // 內容
 public object Content { get; set; } // 當前載入的內容
 public Uri CurrentSource { get; } // 當前內容的URI
 public Uri Source { get; set; } // 當前內容的URI,或者將導航到的內容的URI

 // 查找導航服務
 public static NavigationService GetNavigationService(DependencyObject dependencyObject);
}
  當你知道這些內容之后,就能使用GetNavigationService來獲取寄宿頁面的NavigationWindow的NavigationService引用了:

// HomePage.xaml.cs (codebehind)
public partial class HomePage : Page
{
 void viewHyperlink_Click(object sender, RoutedEventArgs e)
 {
  // 查看訂單
  ViewOrderPage page = new ViewOrderPage(GetSelectedOrder());
  NavigationService ns = NavigationService.GetNavigationService(this);
  ns.Navigate(page);
 }
 Order GetSelectedOrder() { ... }
 ...
}
  這就使得頁面可以執行導航而無需知道宿主的特定信息了。這種需求是如此的普遍,以至于頁面提供了一個特定的輔助屬性NavigationService,它提供的功能相同:

// HomePage.xaml.cs (code-behind)
public partial class HomePage : Page
{
 void viewHyperlink_Click(object sender, RoutedEventArgs e)

 {
  // 查看訂單
  ViewOrderPage page = new ViewOrderPage(GetSelectedOrder());
  this.NavigationService.Navigate(page);
 }

 Order GetSelectedOrder () { ... }
 ...
}
  圖9演示了NavigationWindow、NavigationService和頁面(Page)之間的關系。你可以看到,NavigationWindow重新實現了自己的NavigationService的Content屬性。NavigationWindow不但用這種方法實現了NavigationService的大多數成員,甚至于還增加了一些。例如,你可以通過BackStack和ForwardStack屬性,枚舉"向前"和"向后"導航歷史的內容。

用WPF構建強大的用戶體驗(圖五)
圖9:關系

  不幸的是,你無法建立自定義的、聚合了NavigationService的類型(盡管它是一個公共類型,但是它有內部的構造函數,從而阻止了實例化)。作為代替,你必須依靠三種NavigationService聚合器(aggregator)來寄宿內容。這就是我們所知道的導航器(navigator),包括NavigationWindow、Frame和瀏覽器(僅包括用于Windows Presentation Foundation 1.0的Internet EXPlorer 6 和 7)。當編寫代碼讓頁面使用自己的NavigationService屬性的時候,它就可以寄宿在上面的三種導航器中,而不需要做任何更改,如圖10所示。

用WPF構建強大的用戶體驗(圖六)
圖10:用代碼導航

  也許最令人興奮的是,你發現寄宿在獨立應用程序中的一個頁面忽然就可以寄宿在任何使用Internet Explorer的地方了。 QQread.com 推出各大專業服務器評測 linux服務器的安全性能 SUN服務器 HP服務器 DELL服務器 IBM服務器 聯想服務器 浪潮服務器 曙光服務器 同方服務器 華碩服務器 寶德服務器 XAML瀏覽器應用程序

  NavigationWindow、頁面和超鏈接為用戶在獨立的應用程序中獲得瀏覽器樣式的用戶體驗提供了一條很好的途徑。總而言之,NavigationWindow是一個瀏覽器,雖然它沒有目前的瀏覽器所帶有的所有功能(例如收藏夾、分頁瀏覽等等)。由于大多數用戶都有瀏覽器的知識,他們對提供同等能力、甚至集成瀏覽器的應用程序的感覺會更好。假如你的應用程序從瀏覽器寄宿和超鏈接驅動的環境中受益,那么Windows Presentation Foundation XAML瀏覽器應用程序(XBAP)是我們應該努力的方向。

  為了建立一個XBAP示例應用程序,需要在Visual Studio 2005中建立一個新的.NET框架組件3.0 Web瀏覽器應用程序,并復制示例NavigationWindow文件,就完成工作了。作為結果生成的應用程序將寄宿在Internet Explorer中運行,如圖11所示。

用WPF構建強大的用戶體驗(圖七)
圖11:寄宿在Internet Explorer中的應用程序

  XBAP可以在內部網或Internet上的Web服務器上發布和載入。這使得我們能夠使用ClickOnce部署(它包含在.NET框架組件3.0中)。使用ClickOnce的時候,MSBuild生成最終用戶運行的可執行文件和ClickOnce用于下載和載入可執行文件的兩個清單(manifest)文件。其中一個就是應用程序清單;它帶有.xbap文件擴展名,是用戶希望載入XBAP應用程序時實際瀏覽的內容。請注重,載入過程對于用戶來說是無縫連接的--瀏覽XBAP應用程序的體驗與瀏覽任何瀏覽器中運行的應用程序的體驗是一樣的。

  從Internet上載入一個應用程序的時候,安全性是一個重要的因素。由于這個原因,XBAP是不會被安裝的。而且,XBAP利用.NET框架組件的代碼訪問安全性(CAS),通過強制的安全性平臺防止用戶受到惡意代碼的攻擊--對于從Internet區域載入的應用程序來說,XBAP只能執行許可的事務,是一組受限的操作。而且,假如XBAP試圖執行超出Internet區域許可的功能,就會產生異常,應用程序會停止執行。

  Internet區域許可阻止了Windows Presentation Foundation 1.0中的大量功能,包括顯示窗體、使用SaveFileDialog(保存文件對話框)、注冊表訪問、通過腳本訪問HTML文檔對象模型(DOM)。盡管犧牲了這么多特性來保證CAS保護的XBAP應用程序的利益,你仍然會發現自由支配Windows Presentation Foundation真的非常酷。


  框架(Frame)

  框架把瀏覽器樣式的用戶體驗帶入了內容之中,它可以被其它的導航器(標準的或基于瀏覽器的、菜單或超鏈接驅動的)寄宿。由于它具有很大的靈活性,因此在決定如何使用它的時候,應該由已有的用戶體驗來指導。

  標準的、菜單驅動的應用程序并沒有提供導航文檔樣式內容(例如幫助文件)的最佳模型。超鏈接驅動的方法可能更加適合,并且鏈接可以輕易地嵌入標準的應用程序窗口,如圖12所示。這是使用下面的標記來實現的:

<!--HelpDialog.xaml (markup)-->
<Window ... >
<DockPanel>
<TextBlock
Padding="20,20,20,20"
DockPanel.Dock="Top"
TextWrapping="Wrap"
FontSize="15"
FontWeight="Bold" >
Box Application Help
</TextBlock>
<Frame Padding="20,0,20,0" Source="HelpPageContents.xaml" />
</DockPanel>
</Window>
  作為選擇,框架可以像HTML IFRAME元素一樣被寄宿在Windows Presentation Foundation頁面的內容中,如圖13所示。它的標記類似如下:

<!--HelpPage.xaml (markup)-->
<Page ... >
<DockPanel>
<TextBlock
Padding="20,20,20,20"
DockPanel.Dock="Top"
TextWrapping="Wrap"
FontSize="15"
FontWeight="Bold" >
Box Application Help
</TextBlock>
<Frame ... Source="HelpPageContents.xaml" />
</DockPanel>
</Page>
     用WPF構建強大的用戶體驗(圖八)
  圖12:獨立窗體中的可瀏覽內容

  在默認情況下,當一個框架寄宿在內容中的時候,它就直接或間接地寄宿在另一個導航器中,可以使用父導航器所治理的導航服務。這意味著頁面的導航歷史存儲在它的父導航器的導航歷史中,與父導航器本身的導航歷史存儲在一起。因此,在父導航器的導航歷史能夠導航之前,框架的導航歷史必須向前和向后導航這些內容。但是,當父導航器寄宿的內容在多個頁面之間共享的時候,這并不是壞事。這類似于asp.net的主頁面/子內容。

用WPF構建強大的用戶體驗(圖九)
圖13:內容中寄宿的框架

  另一方面,假如框架中的頁面只由單個邏輯內容組成(例如一個幫助文件而不是多個幫助頁面),這種導航就非常痛苦了。一旦用戶進入幫助并導航到適當的幫助頁面,它一般不希望通過所有瀏覽過的頁面導航回去,而是直接返回先前的父頁面。在這種情況下,你可以通過設置JournalOwnership屬性,指示框架使用自己的導航歷史,如下所示:

<Page ... >
...
<Frame ... JournalOwnership="OwnsJournal" />
...
</Page>
  JournalOwnership屬性是用于設置框架使用哪個"journal(導航記錄)"的(內部的Journal類型封裝了Windows Presentation Foundation中的導航歷史),它可以是下面幾個JournalOwnership枚舉值之一:

enum JournalOwnership
{
Automatic, // 假如由框架或NavigationWindow 寄宿,是"UsesParentJournal"
// 否則是"OwnsJournal"(默認的)。
OwnsJournal, // 框架治理導航歷史
UsesParentJournal // 框架的宿主治理導航歷史
}
  當框架擁有自己的導航歷史的時候,它會顯示自己的導航用戶界面,如圖14所示:

用WPF構建強大的用戶體驗(圖十)
圖14:帶有自己的導航歷史的框架
QQread.com 推出各大專業服務器評測 Linux服務器的安全性能 SUN服務器 HP服務器 DELL服務器 IBM服務器 聯想服務器 浪潮服務器 曙光服務器 同方服務器 華碩服務器 寶德服務器 Windows Presentation Foundation資源

  到目前為止,我們討論了嵌入應用程序部件的頁面。但是,內容可以從很多地方載入--它可能被嵌入了代碼所使用的部件、可能被嵌入一個被引用的部件、或者由一組松散的內容文件組成,根本沒有嵌入任何部件。松散的內容本身可以位于本地磁盤、文件共享、甚至于Web站點上。并且,無論內容是嵌入的還是松散的,它都不一定是頁面;內容可能包括多種媒體,例如圖像、視頻和音頻。最后,內容也不一定屬于某個特定的應用程序。屬于其它Web應用程序的HTML頁面也是可行的。

  這種靈活性答應開發者更簡單地處理大量的現實問題。有時候內容對于應用程序來說足夠非凡,而且該應用程序是如此依靠這個內容,以至于需要把內容嵌入部件中來部署內容和應用程序。有些應用程序的內容經常變換,以至于重新構建部件和重新部署新內容變得不切實際,因而支持松散的內容(由于松散的內容可以位于通常的位置,基于Internet和內部網的XBAP應用程序可以避免下載不必要的部件)。此外,有些內容在多個應用程序之間共享,但是仍然需要保證它們可供使用。

  為了保證靈活性,Windows Presentation Foundation為了唯一標識和載入資源,使用了一種非凡的機制。它不考慮內容的位置或內容是嵌入還是松散的。這種機制的基礎是Pack URI大綱(scheme),它是一種用不同的URI標識應用程序資源的可擴展大綱。Windows Presentation Foundation利用Pack URI大綱來支持幾種用于載入內容的不同的、但是常見的情形。


  在整篇文章中,無論什么時候使用Application.StartupUri 和Hyperlink.NavigateUri,示例代碼都使用Pack URI來標識和載入窗體和頁面:

<!--App.xaml (markup)-->
<Application ... StartupUri="HomePage.xaml" />
  這個例子使用了Pack URI的相對版本,它是一種很好的簡化操作,答應你輸入更少的內容。Pack URI的完整版本如下所示:

pack://application:,,,/HomePage.xaml
  完整的Pack URI由三個要害的部分組成:大綱(pack://)、擁有者(application:)和路徑(,/HomePage.xaml)。其中擁有者描述了擁有資源的容器的類型,而路徑描述了資源與容器的相對位置。"application:"容器是一個真正的部件,而路徑是資源相對部件的根(root)的位置。

  不管使用完整的或相對的Pack URI,它所指向的內容即可以嵌入部件的內部,也可以是存儲在與應用程序執行文件相關的某個位置的松散的XMAL文件。對于一個存放在應用程序可執行文件目錄中的松散XAML頁面來說,其Pack URI如下所示:

pack://application:,,,/HomePage.xaml
  有趣的是,這個松散的XAML文件的Pack URI與嵌入部件的Pack URI相同。為了區分兩者,Windows Presentation Foundation使用了一個基本的解析機制,在查找松散資源之間,它首先在部件中查找嵌入的資源。

  Pack URI還用于訪問那些嵌入被引用的部件中的Windows Presentation Foundation資源,只是有細微的語法差別:

pack://application:,,,/BoxApplicationLibrary;component/HomePage.xaml
  相對的Pack URI等同于:

/BoxApplicationLibrary;component/HomePage.xaml
  Pack URI答應你從應用程序的原始站點(載入應用程序的位置)來定位和載入資源。對于Web服務器上載入的XBAP應用程序來說,讓內容保持在當前位置同把新內容放入應用程序的發布位置一樣簡單。為了訪問原始站點的松散資源,你必須使用另外一個特定類型的Pack URI,它只能使用完整路徑:

pack://siteoforigin:,,,/HomePage.xaml
  你可以導航到頁面(無論是嵌入的還是松散的)的任何一個片段(fragment)。這與Web樣式的片段導航是類似的。通過指定Name屬性,你就可以在頁面上定義片段了,如下所示:

<Page ... >
<TextBlock Name="Paragraph1" TextWrapping="Wrap">
...
</TextBlock>
</Page>
  為了導航到頁面片段,你需要使用另外一種非凡的Pack URI,在頁面URI上附加"#XAMLElementName",如下所示:

HelpPage3.xaml#Paragraph3
  頁面函數(PageFunction)

  由于內容來自于多個位置,而超鏈接驅動的應用程序又答應用戶導航到任何位置,從而使完成一項事務變得非常困難。這是因為超鏈接驅動的應用程序不能輕易地約束用戶導航到特定頁面。無論應用程序提供了多少個超鏈接,用戶仍然可以使用瀏覽器的地址欄導航到任何地方。其結果是,用戶可以離開發起事務的頁面,而不考慮事務是否完成了。在Web世界中,有很多技巧可用于建立類似對話框樣式行為、依靠對話狀態等的Web頁面。不幸的是,這需要大量的開銷。對話框的確可以解決這個問題,但是由于安全性原因,Window不能從應用程序中實例化,例如XBAP的對話框就只能在Internet區域部分信任環境中運行。

  幸運的是,Windows Presentation Foundation通過頁面函數支持模式對話框樣式的機制。它們被封裝為泛化的PageFunction類型,直接衍生自Page。因而PageFunction的樣子與頁面類似,它的建立方式也相似,如下段所示。

  代碼:PageFunction

<!--OrderABoxPageFunction.xaml (markup) -->
<PageFunction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BoxApplicationXBAP"
x:Class="BoxApplicationXBAP.OrderABoxPageFunction"
x:TypeArguments="local:Order"
WindowTitle="Box Application - Order a Box" >
...
<!--Content-->
...
<PageFunction>

// OrderABoxPageFunction.cs (code-behind)
public partial class OrderABoxPageFunction:
PageFunction<Order> { ... }
  這個特定的頁面函數的目標是收集新訂單的信息,它被Order封裝了。由于典型情況下事務都是這樣操作數據的,PageFunction是一個泛型(generic),并被聲明用于操作特定的數據(標記中特定的x:TypeArguments屬性)。假如x:TypeArguments的值和泛化的PageFunction類型的參數不匹配,就會出現編譯錯誤。

  調用PageFunction的頁面需要實例化PageFunction并手動導航到該頁面上:

// HomePage.cs (codebehind)
public partial class HomePage : Page
{
 void orderHyperlink_Click(object sender, RoutedEventArgs e)
 {
  OrderABoxPageFunction pageFunction = new OrderABoxPageFunction();

  pageFunction.Return += new ReturnEventHandler<Order>(OrderABoxPageFunction_Returned);
  this.NavigationService.Navigate(pageFunction);
 }
 ...
}
  接下來,PageFunction在給調用頁面返回結果之前,必須答應用戶完成頁面:

// OrderABoxPageFunction.cs (codebehind)
public partial class OrderABoxPageFunction:
PageFunction<Order>
{
void orderHyperlink_Click(object sender, RoutedEventArgs e)
{
// 返回訂單
this.OnReturn(new ReturnEventArgs<Order>(this.order));
}
void cancelHyperlink_Click(object sender, RoutedEventArgs e)
{
// 取消訂單
this.OnReturn(null);
}
...
}
  接下來調用PageFunction.OnReturn返回,傳遞一個泛化的ReturnEventArgs實例。假如事務被接受了,它就包含一個PageFunction所操作的類型實例。否則,它就是空的。為了檢測PageFunction的返回,并獲取ReturnEventArgs和其數據,調用頁面需要處理PageFunction.Returned事件,如下段代碼所示。被返回的數據存放在Returned事件處理程序的ReturnEventArgs參數的Result屬性中。

  代碼:PageFunction.Returned

// HomePage.cs (code-behind)
public partial class HomePage : Page
{
 // 載入頁面函數
 void orderHyperlink_Click(object sender, RoutedEventArgs e)
 {
  OrderABoxPageFunction pageFunction = new OrderABoxPageFunction();
  pageFunction.Return += new ReturnEventHandler<Order>(OrderABoxPageFunction_Returned);
  this.NavigationService.Navigate(pageFunction);
 }
 // 處理頁面函數的返回
 void OrderABoxPageFunction_Returned(object sender, ReturnEventArgs<Order> e)
 {
  if (e != null) this.orders.Add(e.Result);
 } 
 ...
}
  你可能希望在事務完成之后,確保PageFunction從導航歷史中移除。這只需要一個簡單的配置:

<!--OrderABoxPageFunction.xaml (markup) -->
<PageFunction RemoveFromJournal="True" ... >
...
<!--Content-->
...
<PageFunction>
  通過從導航歷史中刪除頁面函數,你可以阻止用戶導航回該頁面函數。這是非常重要的,因為假如不這樣處理,用戶就可能修改那些已經發生改變的數據,從而造成潛在的數據不一致風險。

  我們的位置

  Windows Presentation Foundation應用程序模型是非常靈活的。它支持標準的和瀏覽器寄宿的應用程序--它們兩者都支持菜單驅動和超鏈接驅動的導航。此外,應用程序的內容可以被封裝到應用程序的部件、被引用的部件或某些位置的松散文件中。總而言之,在Windows Presentation Foundation應用程序模型中建立的用戶體驗類型僅受個人選擇的限制。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 91精品久久香蕉国产线看观看 | 日韩高清影视 | 少妇一级淫片免费放播放 | 亚洲91精品 | 精品无吗乱吗av国产爱色 | 国产午夜精品一区二区三区在线观看 | 3xxx| 久久久久久久久久久久网站 | 久久91亚洲人成电影网站 | 久久成人国产精品入口 | 久久精品日韩一区 | 好吊色37pao在线观看 | 黄色久 | 成人午夜精品久久久久久久蜜臀 | 91成人免费视频 | 久久久久久久久久久久网站 | 在线中文字幕亚洲 | 水卜樱一区二区av | 91精品国产综合久久久动漫日韩 | 一级黄色大片在线观看 | 国产欧美日韩在线不卡第一页 | 久久精品亚洲一区 | 日本成年免费网站 | 黄网站免费观看视频 | 久久福利剧场 | 欧美精品 | 国产午夜精品一区二区三区视频 | 国产女同玩人妖 | 亚洲网站在线观看 | 欧美一级在线看 | xxxx欧美视频 | 亚洲精品自在在线观看 | 二区三区四区 | 在线亚洲欧美 | 亚洲精品日韩色噜噜久久五月 | 91九色论坛 | 一级大片久久 | 亚洲一区中文字幕 | 国产寡妇xxxxxxxx性开放 | 久草在线视频免费播放 | 一级成人毛片 |