いわゆる分離設計ですかね。UWP において x:Bind はパフォーマンス向上に必要ですが、それを使いたい、となると DataTemplate
として別途定義していくことになります。しかし、そうなると 1 ファイルにすし詰めになるのでは? という疑問がある人への解消方法です。
概要
- そもそも
x:Bind
とはなんなの? - コード ビハインドってなんで動いてるか知ってる?
- 同じようにすればいけるよね?
- 完成 & まとめ
1. そもそも x:Bind
とはなんなの?
コンパイル時 Bindingです。
言ってしまえばコレ。このコードは分離された (parted) なコード ビハインドに生成されます。
2. コード ビハインドってなんで動いてるか知ってる?
ページにはコードビハインドが必須と思ってる方もいそうですが、実のところ、xaml テーマとか見てもらったらわかるんですけど、コードビハインドって概念がそもそも存在しないものもありますよね。
じゃあ何トリガーに起動してるの? って疑問があると思うんです。単純です。 x:Class
<Page x:Class="XBindLecture.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XBindLecture"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> </Grid> </Page>
そう、一番上にある x:Class="XBindLecture.MainPage"
がコード ビハインド生成の手がかりなわけです。
3. 同じようにすればいけるよね?
ResoruceDictionary
にもこの論が通用します。例えば空のプロジェクトに DetailView.xaml
っていう ResourceDictionary
なファイル作ってみますか。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XBindLecture"> </ResourceDictionary>
ここに、まず x:Class
をつけます。名前は XBindLecture.Views.DetailView
でいいでしょう。
<ResourceDictionary x:Class="XBindLecture.Views.DetailView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XBindLecture"> </ResourceDictionary>
次に DetailView.xaml.cs
というコードビハインドを記述するファイルを生成します。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace XBindLecture.Views { class DetailView { } }
これをそれっぽく (デフォルト テンプレートのように) します。
using Windows.UI.Xaml; namespace XBindLecture.Views { public sealed partial class DetailView : ResourceDictionary { public DetailView() { this.InitializeComponent(); } } }
こんな感じで準備おkです。
まあそうですね、簡略化するために以下のモデル考えますか。名前と年齢と性別ね。
public enum SexType : byte { Unknown = 0, Male, Female }; public sealed class Person { public string Name { get; } public ushort Age { get; } public SexType Sex { get; } } public sealed class PersonViewModel { public Person OriginalSource { get; } public string Name => this.OriginalSource.Name; public string Age => this.OriginalSource.Age.ToString(); public string Sex => this.OriginalSource.Sex.ToString(); }
このモデルに即してテキトーな UI 作ります。
つくりました。
<ResourceDictionary x:Class="XBindLecture.Views.DetailView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="using:XBindLecture.ViewModels"> <DataTemplate x:DataType="vm:PersonViewModel"> <StackPanel> <TextBlock Text="{x:Bind Name}" /> <TextBlock Text="{x:Bind Age}" /> <TextBlock Text="{x:Bind Name}" /> </StackPanel> </DataTemplate> </ResourceDictionary>
これを表示する DetailPage
を作りましょう。
つくりました。
<Page x:Class="XBindLecture.Views.DetailPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:v="using:XBindLecture.Views" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Page.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <v:DetailView /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Page.Resources> <ContentPresenter EntranceNavigationTransitionInfo.IsTargetElement="True" Content="{x:Bind Person}" ContentTemplate="{StaticResource ProfileViewTemplate}" /> </Page>
ポイントは <v:DetailView />
とするところです。
注
<ResourceDictionary Source="DetailView.xaml" />
でよさそうに見えますが、これでは xaml loader が xaml を読み込むだけで、インスタンスによる初期化が実行されません。つまりコードビハインド類が実行されないので、正しく binding ができないようになります。
あとはメインページでも同じようなことをすればいいので繰り返しになるので省略します。
4. 完成 & まとめ
ということで完成です。UWP には必須の技術ですね!
プログラムもあげてます! こちらもぜひ!
参照したサイト
http://igrali.com/2015/06/14/how-to-use-compiled-bindings-xbind-from-a-resource-dictionary/
Thanks to igor ralic.