[Universal Apps] 共用 Basic Page 的範本

Universal Apps 方案帶來了同時開發 Winndows 和 Windows Phone App 的便利性, 但在使用的過程中發現了一個小小的缺憾, 就是在 Page 共用這一點還不夠完整, 在預設的狀況下能在 Shared 專案中被新增的頁面範本只有空白頁面, 然而空白頁面缺乏了一些可以讓我們減少開發時間的既有程式碼. 有一種變通的方式是在 Windows 或 Windows Phone 專案中使用基本頁面 (Basic Page) 範本建立 Page 後再移動 Shared 專案, 繼之加上大量的修改, 為了節省這些時間, 我就動手做了一個可以共用基本頁面的專案範本和頁面範本.

        Universal Apps 方案帶來了同時開發 Windows 和 Windows Phone App 的便利性, 但在使用的過程中發現了一個小小的缺憾, 就是在 Page 共用這一點還不夠完整, 在預設的狀況下能在 Shared 專案中被新增的頁面範本只有空白頁面, 然而空白頁面缺乏了一些可以讓我們減少開發時間的既有程式碼. 有一種變通的方式是在 Windows 或 Windows Phone 專案中使用基本頁面 (Basic Page) 範本建立 Page 後再移動 Shared 專案, 繼之加上大量的修改, 為了節省這些時間, 我就動手做了一個可以共用基本頁面的專案範本和頁面範本.

 

 

        1. 了解 Windows 和 Windows Phone 頁面上有甚麼不同

        (1) 第一個不同點在於標題的區塊, Windows 和 Windows Phone 在標題區塊上的配置有很大的差異, 另一個在標題上的差異點是不同於 Windows Phone 擁有硬體後退按鍵,  Windows 是使用軟體後退按鍵,  而一般這個後退按鍵會放在標題區塊, 各位可以在兩個專案分別使用基本頁面範本建立一個 Page, 然後仔細觀察其差異, 或參考下方的 xaml code

 

        Windows 的標題區塊

   1: <Grid>
   2:     <Grid.ColumnDefinitions>
   3:         <ColumnDefinition Width="120"/>
   4:         <ColumnDefinition Width="*"/>
   5:     </Grid.ColumnDefinitions>
   6:     <Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
   7:                 Style="{StaticResource NavigationBackButtonNormalStyle}"
   8:                 VerticalAlignment="Top"
   9:                 AutomationProperties.Name="Back"
  10:                 AutomationProperties.AutomationId="BackButton"
  11:                 AutomationProperties.ItemType="Navigation Button"/>
  12:     <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
  13:                 IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>
  14: </Grid>

 

 

        Windows Phone 的標題區塊

   1: <StackPanel Grid.Row="0" Margin="19,0,0,0">
   2:     <TextBlock Text="MY APPLICATION" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
   3:     <TextBlock Text="page title" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
   4: </StackPanel>

 

 

 

        (2) 背景的設定, 在我之前的文章 [Universal 不一樣] Page.Background 中有提到 Page.Background 這個屬性只對 Windows Phone Apps 有作用, 在 Windows Apps 中, 背景必須在 Page Content 的第一層容器中設定.

 

 

        (3) 內容的邊界配置, 由於標題區塊的邊界設定的不同, 為了美觀上的因素, 我們所製作的內容在兩種專案也應該要設定不同的邊界, 才能讓兩個專案的內容呈現都是比較正確的.

 

 

        2. 製作 Windows 標題區塊的使用者控制項 (UserControl)

        Windows Apps 的標題區塊比較複雜, 首先在 Windows 專案中加入一個新增項目 (使用者控制項), 我將其命名為 PageTitleControl, 建立如下的 xaml code

   1: UserControl
   2:     x:Class="BasicApp5.PageTitleControl"
   3:     x:Name="pagetitlecontrol"
   4:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   5:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   6:     xmlns:local="using:BasicApp5"
   7:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   8:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   9:     mc:Ignorable="d"   
  10:     d:DesignHeight="300"
  11:     d:DesignWidth="400">
  12:  
  13:     <Grid Height="140">
  14:         <Grid.ColumnDefinitions>
  15:             <ColumnDefinition Width="120"/>
  16:             <ColumnDefinition Width="*"/>
  17:         </Grid.ColumnDefinitions>
  18:         <Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pagetitlecontrol}"
  19:                         Style="{StaticResource NavigationBackButtonNormalStyle}"
  20:                         VerticalAlignment="Top"
  21:                         AutomationProperties.Name="Back"
  22:                         AutomationProperties.AutomationId="BackButton"
  23:                         AutomationProperties.ItemType="Navigation Button"/>
  24:                
  25:         <TextBlock x:Name="pageTitle" x:Uid="PageTitle" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
  26:                         IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>
  27:     </Grid>
  28: </UserControl>

 

 

        然後修改其後置程式碼

   1: public sealed partial class PageTitleControl : UserControl
   2: {
   3:     private NavigationHelper _navigationHelper;
   4:     public NavigationHelper NavigationHelper
   5:     {
   6:         get { return _navigationHelper; }
   7:         set
   8:         {
   9:             _navigationHelper = value;               
  10:         }
  11:     }
  12:   
  13:  
  14:     public PageTitleControl()
  15:     {
  16:         this.InitializeComponent();
  17:     }
  18:    
  19: }

 

        3. 製作 Windows Phone 的標題區塊, 這個就簡單多了, 在 Windows Phone 專案建立一個命名和 Windows 專案中相同的使用者控制項, 並修改其 xaml code 即可

   1: <UserControl
   2:     x:Class="BasicApp5.PageTitleControl"
   3:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   4:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   5:     xmlns:local="using:BasicApp5"
   6:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   7:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   8:     mc:Ignorable="d"
   9:     d:DesignHeight="300"
  10:     d:DesignWidth="400">
  11:  
  12:     <Grid>
  13:         <StackPanel Grid.Row="0" Margin="19,0,0,0">
  14:             <TextBlock x:Name="pageTitle" x:Uid="Pagetitle" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
  15:             
  16:         </StackPanel>
  17:     </Grid>
  18: </UserControl>

 


		

		

		

 

 

        4. 在 Windows 和 Windows Phone 專案中分別建立資源字典檔案命名為 DefaultResources.xaml , 內容如下

        Windows

   1: <ResourceDictionary
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:local="using:BasicApp5">
   5:     <Thickness x:Key="ContentMargin">48,0,24,0</Thickness>
   6:     <SolidColorBrush x:Key="PageBackground"  Color="Transparent"/>
   7:     <SolidColorBrush x:Key="LayoutRootBackground" Color="#FF1D1D1D"/>
   8: </ResourceDictionary>

 

 

        Windows Phone

   1: <ResourceDictionary
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:local="using:BasicApp5">
   5:     <Thickness x:Key="ContentMargin" >19, 9.5, 19, 0</Thickness>
   6:     <SolidColorBrush x:Key="PageBackground"  Color="{ThemeResource PhoneBackgroundColor}"/>
   7:     <SolidColorBrush x:Key="LayoutRootBackground" Color="Transparent"/>
   8: </ResourceDictionary>

 

 

        5. 修改 App.xaml 加入自訂的資源字典

   1: <Application
   2:     x:Class="BasicApp5.App"
   3:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   4:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   5:     xmlns:local="using:BasicApp5">
   6:    <Application.Resources >
   7:         <ResourceDictionary >
   8:             <ResourceDictionary.MergedDictionaries>
   9:                 <ResourceDictionary Source="Common/DefaultResources.xaml"/>
  10:             </ResourceDictionary.MergedDictionaries>
  11:         </ResourceDictionary>
  12:     </Application.Resources>
  13: </Application>

 

 

        6. 在 Shard 專案中建立共用的 Page

   1: <Page    
   2:     x:Class="BasicApp5.MainPage"
   3:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   4:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   5:     xmlns:local="using:BasicApp5"
   6:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   7:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   8:     mc:Ignorable="d"  Background="{StaticResource PageBackground}">
   9:  
  10:     <Grid x:Name="LayoutRoot" Background="{StaticResource LayoutRootBackground}">
  11:  
  12:         <Grid.ChildrenTransitions>
  13:             <TransitionCollection>
  14:                 <EntranceThemeTransition/>
  15:             </TransitionCollection>
  16:         </Grid.ChildrenTransitions>
  17:  
  18:         <Grid.RowDefinitions>
  19:             <RowDefinition Height="Auto"/>
  20:             <RowDefinition Height="*"/>
  21:         </Grid.RowDefinitions>
  22:  
  23:         <!-- 標題面板 -->
  24:         <Grid Grid.Row="0">
  25:             <local:PageTitleControl x:Name="pagetitle"/>
  26:         </Grid>
  27:  
  28:         <!--TODO: 內容應該放在下列格線內-->
  29:         <Grid Grid.Row="1" x:Name="ContentRoot" Margin="{StaticResource ContentMargin}">
  30:             
  31:         </Grid>
  32:     </Grid>
  33: </Page>

 

 

 

 

 

 

        可以看到我們在標題面板是使用前面所建立的使用者控制項, 背景和邊界的設定則是來自於自訂的資源字典.

 

 

        接著修改一下頁面的後置程式碼的建構函式, 因為 Windows 的軟體後退按鍵和頁面的 NavigationHelper 有繫結, 所以必須特別處理

   1: public MainPage()
   2: {
   3:     this.InitializeComponent();
   4:  
   5:     this.navigationHelper = new NavigationHelper(this);
   6:     this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
   7:     this.navigationHelper.SaveState += this.NavigationHelper_SaveState;           
   8: #if WINDOWS_APP
   9:     pagetitle.NavigationHelper = this.navigationHelper;            
  10: #endif
  11: }

 

 

        大致上這樣就完成了共用頁面的範本. 最後我將這個範本做成了 VSIX , 以便於直接安裝, 各位可以點選下載範本下載後執行 vsix 檔案. 會在 Visual Studio 2013 (需要 update 2 以上) 中加入以下兩個範本

        方案範本

        image

 

        頁面範本

        image

 

2014/09/18 新增: 在 Visual Studio 可以使用搜尋擴充功能的方式安裝
VSG