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 以上) 中加入以下兩個範本
方案範本
頁面範本