というわけで、Metro 開発始めました。 Windows 8 Consumer Preview と Visual Studio 11 Express for Windows 8 を開発環境として利用してアプリケーションを開発する上で、テンプレートから Grid Application テンプレートで開発スタートしてみたので、このテンプレートの基本構成その他読み取った物をつらつらとメモがきしてみます。
プロジェクトのファイル構成
パッと見でCommon, DataModel に多少の C# ファイルがある事のトップに XAML ファイルがあり、XAMLに関連づいた C#ファイルがあります。

Common/BindableBase.cs
Common の BindableBase.cs が INotifyPropertyChanged 等データバインディングの為の基本実装をしているようです。INotifyPropertyChanged の実装コードのシグネチャとしては以下のような感じ
protected bool SetProperty<T>(
ref T storage,
T value,
[CallerMemberName] String propertyName = null)
さっそくC#の新機能が使われていますね CallerMemberName 属性で SetProperty はプロパティ名を引きとっています。
ref T storage で指定されたフィールドに value で指定された値を突っ込み OnPropertyChanged でイベントを発火するというのが基本になってます。 object.Equals で比較して変化の無い場合にはフィールド更新およびイベントの発火をショートカットする様になっています。
object.Equals で比較しているので null チェックが行われてから obj1.Equals(obj2) と同義になりますね。
object Equals( object other ) ですので、object への暗黙変換が発生し、boxing が発生するなんて細かい事に気づいてチューニングする必要は殆どありません。この程度で影響があるとしたらプロパティの連鎖更新が大量に発生する酷いモデルをあなたが作っているという事です。
酷いモデルもあるはずって事でちょっと見てみたのですが、何かがオカシイです。

System.Runtime.dll の System.Type をILDASM で見た所、IsClass が無いですよね。
ドキュメントを見た限りでは IsClass は存在する事になっているのですが見当たりません。
IsClass が false であれば object への暗黙変換で boxing が発生するからそれを避けるとかいうコードを書きたくてもどうにもなりません。どうにもならないので次のソースを見る事にします。
Common/BooleanNegationConverter.cs
とりあえずbool値を反転するIValueConverterですねテンプレート内の何処かで使われてる気はしません(検索でヒットせず、コメントアウトしてビルド、実行で問題無し)、うざいと思う人は消しちゃって良いでしょう。ぶっちゃけてノイズだと思います。
Common/BooleanToVisibilityConverter.cs
同じく bool 値をVisibility に変換する IValueConverterで、同様にどこも使ってません。なぜ Common に共通定義してるのか解らない物なので邪魔ならば消してしまいましょう。
Common/LayoutAwarePage.cs
テンプレート内に定義されている各 XAML ページの基本クラスになっています。
いくつかイベントハンドラーが定義されています、GoHome は Frame.CanGoBack が true の間 Frame.GoBack を繰り返すという形で実装されています。
FrameはWindows.UI.Xaml.Controls.Frameで、Metro UI Framework において進む、戻るの一連のUIの進行状況を管理する仕組みを構成しています。(しかし、MSDNのメニューシステム、なんとかならんのでしょうか、日本語でMSDN使うと翻訳できてる部分しかメニューに出てこなくてメニューが全くつながらずで困ります)
このテンプレートでのナビゲーションはこのFrameに一任されていますので正しくFrameを使う事という事が画面遷移に関しての必要事項でありテスト項目となりそうですね。
残念ながらFrameはINavigateを実装していますが、INavigate がカバーしているメソッドセットには CanGoBack や GoBack は含まれていませんのでFakeするのに多少困る面が残りそうです。
Common/RichTextCollumns.cs
Panelを派生したカスタムコントロールによって最終的な詳細ビューで使われるリッチテキスト表示を実装しています。これがここにある意味は「お前らこれぐらいのコントロール自分で書けよ、サンプルをテンプレートに入れてるんだから」って事でしょうね。
完全な表示用コントロールなのでサイズ計算ロジックの置き換えである MeasureOverride ArrangeOverride が主体で後は関連プロパティを実装しているだけですね。
サイズ計算ロジックとしては単純に LoadContent が返した内容をRichTextBlockOverflowとして見て OverflowContent があれば次のブロックを生成する事の繰り返しです。
この実装の中には仮定が含まれている事がコードの見た目で解ります。
まずRichTextBlockOverflow へのキャストです。キャストは戻り値の型が違えば失敗しますが LoadContent が帰した物をノーチェックでキャストしていますので、DataTemplate.LoadContentはRichTextBlockOverflow を返さなければなりません。
そこのところに防御的なアプローチは全く見えませんので全くの専用コントロールという事が見て取れます。
DataModel/SampleDataSource.cs
いわゆる ViewModel と Model のハイブリッドな物がここに実装されています。アプリケーションにする場合には何かしら意味のあるデータにする為にまず此処に手を入れる事になるでしょう。
Model に相当しているのは SampleDataSource クラスです、ここで他のクラスのインスタンスを単純にnew しまくってデータモデルを構成しています。何かしらのサーバないしはデータを持っている物を検索して new する様に変更すればアプリケーションは意味あるデータを表示する様になるでしょう。
SampleDataGroup と SampleDataItem が共通基底 SampleDataCommon から派生されていてそれぞれグループと要素を表現しています。
SampleDataGroup が ObservableCollection<SampleDataItem> を保持し、SampleDataItem はコンテンツとなる文字列を持っています。SampleDataCommon は共通となるタイトルやイメージを保持しているわけでそれほど面倒な構造ではありません。
SampleDataCommon が Common 配下で定義された BindableBase から派生されていますのでINotifyPropertyChanged でのプロパティ更新通知がサポートされます。
アプリケーションとしては完全な参照系なので SampleDataSource であるモデルには更新系が存在しません。サンプルとしてはいかがなものかとか言いませんよね、自分で考えやがれと突き放されただけです。
所でフォルダがDataModel で名前空間がData って気持ち悪くねぇ?気持ち悪い人はテンプレートを直しやがれが例題なのでしょうか?
App.xaml と App.xaml.cs
xaml 側は Common/StandardStyles.xaml をResourceDictionaryとして取り込んでいるほかAppName としてアプリケーション名をリソース定義しているだけです。アプリケーション固有のリソース定義したければここで好きにしやがれって事でしょう。
App.xaml.cs がアプリケーションの開始処理としての非常に重要な事を実装しています。
「コードビハインドにコードを書いたら負けだと思っている」な自分としては非常に気になるわけですが、実装内容としては OnLaunched でモデルからのデータローディング(PreviousExecutionState が Terminated であれば Suspendからの復帰も)と rootFrameの生成と初期Navigate、 OnSuspending でのアプリケーション状態の保存なわけで絶対にアプリケーション固有な領域なので致し方ないかなな気持ちもあります。
他の xaml と xaml.cs
基本的な表示等はすべて xaml側での記述になっておりxaml.csでデータをコネコネは基本しない構造になっています。xaml.cs での記述内容は OnNavigateTo で画面遷移してきた時にDataContextに結び付けられている DefaultViewModel にデータを突っ込んでいる事と Click での FrameへのNavigate 発行だけです。
思いつく例題とか
- Common 名前空間に含まれる実装をクラスライブラリに切り出ししなさい。
特にBindableBase はこの先あなたのお供として延々育てていくべきコードになるでしょう。これをあなたが育て続けられる環境に移すか他のMVVMインフラを導入するかの選択時期は早々に訪れるはずです。どっちにしても作ったアプリケーション毎に微妙に異なる Commonを延々メンテナンスするのが嫌ならCommonの実装が共有できるようになっていなければなりません。
- SampleDataSource.cs に相当するソースを自動生成するテキストテンプレートを記述しなさい。
1をやると意味が出ますが各種データモデルの細かい修正でプロパティの所の記述をチマチマ SetProperty 呼び出しするとか書いてると疲れますのでもっと軽い仕組みにしましょう。
Office XML を解釈してExcel 方眼紙からデータモデルの実装が自動で起こせるとかすると Excel でプログラムが書けます(やめましょう)し、テキストテンプレートでSQL Server のスキーマを参照すればDBテーブルを射影するのに必要なデータモデルが生成できる事になります。
- Suspending / Lounching をちゃんとして、Suspendされて終了された時に元の場所に戻る様にしようよ。