先日は、軽く作っただけですが、ちょっと改良してみようと思います。
Windows ストア アプリでページ間で共通の見た目を簡単に作りたい - かずきのBlog@hatena
ページのタイトルをPageTemplateコントロールのプロパティで設定できるようにする
昨日の段階ではXAML内で以下のようにDataContextにAppNameというプロパティがあるという前提でハードコーディングしていました。これだと、ちょっと自由度が低すぎるのでPageTemplateにPageTtleという名前のプロパティを用意して、それを通して設定できるようにしたいと思います。バインドできたほうがMVVM的にも自由がききそうなので依存関係プロパティとしてPageTemplateプロパティに定義します。
publicstring PageTitle
{
get { return (string)GetValue(PageTitleProperty); }
set { SetValue(PageTitleProperty, value); }
}
publicstaticreadonly DependencyProperty PageTitleProperty =
DependencyProperty.Register("PageTitle",
typeof(string),
typeof(PageTemplate),
new PropertyMetadata(null));
そして、Generic.xamlのページタイトルのTextBlockを以下のように書き換えます。
<TextBlock xName="pageTitle"Text="{Binding AppName}"Style="{StaticResource HeaderTextBlockStyle}"GridColumn="1"IsHitTestVisible="false"TextWrapping="NoWrap"VerticalAlignment="Bottom"Margin="0,0,30,40"/><TextBlock xName="pageTitle"Text="{TemplateBinding PageTitle}"Style="{StaticResource HeaderTextBlockStyle}"GridColumn="1"IsHitTestVisible="false"TextWrapping="NoWrap"VerticalAlignment="Bottom"Margin="0,0,30,40"/>
こうすると、このPageTemplateコントロールを使う側で好きなようにXAMLから(またはPageTitleプロパティと何かをバインドすることでViewModelから)設定出来るようになります。
<PagexName="pageRoot"xClass="TemplateApp.MainPage"DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"xmlnslocal="using:TemplateApp"xmlnscommon="using:TemplateApp.Common"xmlnsd="http://schemas.microsoft.com/expression/blend/2008"xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"mcIgnorable="d"><localPageTemplate PageTitle="XAMLから指定したタイトル"><Grid></Grid></localPageTemplate></Page>
デザイナ上でも表示を確認できます。
![f:id:okazuki:20140109212310p:plain f:id:okazuki:20140109212310p:plain]()
戻るボタンを押したときの挙動
もう1つコントロール内にハードコーディングされているものとして、戻るボタンのコマンドがあります。
<Button xName="backButton"Margin="39,59,39,0"Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
これもPageTitleと同様に外部から指定できるようにするのがスマートでしょう。ということで、PageTemplateクラスにICommand型のGoBackCommandプロパティを作成します。
public ICommand GoBackCommand
{
get { return (ICommand)GetValue(GoBackCommandProperty); }
set { SetValue(GoBackCommandProperty, value); }
}
publicstaticreadonly DependencyProperty GoBackCommandProperty =
DependencyProperty.Register("GoBackCommand",
typeof(ICommand),
typeof(PageTemplate),
new PropertyMetadata(null));
Generic.xamlの中で戻るボタンをTemplateBindingを使ってバインドするように修正します。
<Button xName="backButton"Margin="39,59,39,0"Command="{TemplateBinding GoBackCommand}"
これで、外部から戻るボタンの挙動を差し替えることができます。NavigationHelperクラスに依存しなくなりました。NavigationHelperクラスのGoBackCommandをページからBindingすれば、従来通りの動きをさせることも可能です。
<localPageTemplate PageTitle="XAMLから指定したタイトル"GoBackCommand="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"><Grid></Grid></localPageTemplate>
見た目をカスタマイズしたいのが一か所じゃない場合
今回の例では、タイトルから下のコンテンツ部分がページ固有のカスタマイズ領域ですが場合によっては、ヘッダーの一部の領域もページごとに固有のコンテンツを置きたいということもあると思います。そういうときは、以下のようにすればOKです。
PageTemplateクラスにカスタマイズコンテンツを格納するためのプロパティと、それの表示を定義するDataTemplate型のプロパティを定義してやります。今回はフッター部に一部カスタマイズ領域を設けるという感じで以下のような名前のプロパティを定義しました。
publicobject FooterContent
{
get { return (object)GetValue(FooterContentProperty); }
set { SetValue(FooterContentProperty, value); }
}
publicstaticreadonly DependencyProperty FooterContentProperty =
DependencyProperty.Register("FooterContent",
typeof(object),
typeof(PageTemplate),
new PropertyMetadata(null));
public DataTemplate FooterContentTemplate
{
get { return (DataTemplate)GetValue(FooterContentTemplateProperty); }
set { SetValue(FooterContentTemplateProperty, value); }
}
publicstaticreadonly DependencyProperty FooterContentTemplateProperty =
DependencyProperty.Register("FooterContentTemplate",
typeof(DataTemplate),
typeof(PageTemplate),
new PropertyMetadata(null));
Generic.xamlには、GridのRowを1行たして、そこにBorderあたりでくるんだContentControlを置いて上記で作成したプロパティをContentとContentTemplateにバインドします。
<ControlTemplate TargetType="local:PageTemplate"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><GridChildrenTransitions><TransitionCollection><EntranceThemeTransition/></TransitionCollection></GridChildrenTransitions><GridRowDefinitions><RowDefinition Height="140"/><RowDefinition Height="*"/><RowDefinition Height="Auto"/></GridRowDefinitions><Grid><GridColumnDefinitions><ColumnDefinition Width="120"/><ColumnDefinition Width="*"/></GridColumnDefinitions><Button xName="backButton"Margin="39,59,39,0"Command="{TemplateBinding GoBackCommand}"Style="{StaticResource NavigationBackButtonNormalStyle}"VerticalAlignment="Top"AutomationPropertiesName="Back"AutomationPropertiesAutomationId="BackButton"AutomationPropertiesItemType="Navigation Button"/><TextBlock xName="pageTitle"Text="{TemplateBinding PageTitle}"Style="{StaticResource HeaderTextBlockStyle}"GridColumn="1"IsHitTestVisible="false"TextWrapping="NoWrap"VerticalAlignment="Bottom"Margin="0,0,30,40"/></Grid><ContentPresenter GridRow="1" /><Border GridRow="2"Background="#FFBD4C4C"><ContentControl Content="{TemplateBinding FooterContent}"ContentTemplate="{TemplateBinding FooterContentTemplate}"HorizontalContentAlignment="Stretch"/></Border></Grid></ControlTemplate>
FooterContentプロパティに適当な値をつっこんだらそれがそのまま表示されますし、FooterContentTemplateをデザイナから編集して、ぽとぺたでカスタマイズすることもできます。
<localPageTemplate PageTitle="XAMLから指定したタイトル"GoBackCommand="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"><localPageTemplateResources><DataTemplate xKey="DataTemplate1"><Border BorderBrush="Black"BorderThickness="1"><Grid><Button Content="Button"HorizontalAlignment="Stretch" /></Grid></Border></DataTemplate></localPageTemplateResources><localPageTemplateFooterContentTemplate><StaticResource ResourceKey="DataTemplate1"/></localPageTemplateFooterContentTemplate><Grid><Button Content="Button"HorizontalAlignment="Left"Margin="115,33,0,0"VerticalAlignment="Top" /></Grid></localPageTemplate>
![f:id:okazuki:20140109220339p:plain f:id:okazuki:20140109220339p:plain]()
当然ですが実行してみてもデザイナでデザインした通りに画面の下にボタンが出ています。
![f:id:okazuki:20140109220458p:plain f:id:okazuki:20140109220458p:plain]()