過去記事
マークアップ拡張
XAMLは、XMLをベースにして作られた言語なので、複雑な構造をもったオブジェクトでもタグを入れ子にしていくことで柔軟に定義できます。しかし、XMLは書く人にとっては冗長でちょっとした内容でも記述量が跳ね上がるといった問題点もあります。しかも、それがよく書くものだったときには少しうんざりしてしまいます。XAMLでは、マークアップ拡張という機能を使うことによって、本来は大量のXMLを書かなければいけないところを簡潔に記述できるようにする機能が提供されています。また、マークアップ拡張を使ってXMLで記述できないような値を取得して設定することもできます。
マークアップ拡張は、XAMLの属性の値を指定するときに{ではじまり}で終わる形で記述します。こうすることで、System.Windows.Markup.MarkupExtensionから継承したクラスに値の生成を委譲することが出来ます。WPFでは組み込みで{Binding Path=…}や{StaticResource …}や{DynamicResource …}など様々な種類のマークアップ拡張が定義されています。これらを使うことで、XAMLの記述を簡潔に行ったり、プロパティに設定する値を特殊な方法で取得することが出来るようになります。
例えば、以下のようなItemという名前のクラスのIdというプロパティにXAMLから毎回ユニークになるような値を設定しないといけないような場合に、マークアップ拡張を使うことができます。マークアップ拡張とItemクラスのコードを以下に示します。
namespace CollectionXaml { using System; using System.Windows.Markup; public class Item { public string Id { get; set; } } // Idを提供するマークアップ拡張 public class IdProviderExtension : MarkupExtension { // Idのプリフィックス public string Prefix { get; set; } // 値を提供するロジックを記述する public override object ProvideValue(System.IServiceProvider serviceProvider) { return Prefix + Guid.NewGuid().ToString(); } } }
IdProviderExtensionというクラスがマークアップ拡張のクラスになります。{IdProvider Prefix=hoge}のように使用します。実際にItemクラスのIdプロパティに指定したXAMLは以下のようになります。
<Item xmlns="clr- namespace:MarkupExtensionSample;assembly=MarkupExtensionSample" Id="{IdProvider Prefix=item-}" />
このXAMLを2回読み込んでIdの値を表示してみます。
namespace MarkupExtensionSample { using System; using System.Windows.Markup; class Program { static void Main(string[] args) { // XAMLを読み込んでIdを表示 var item = XamlReader.Load( typeof(Program).Assembly.GetManifestResourceStream("MarkupExtensionSample.Item.xaml")) as Item; Console.WriteLine(item.Id); // 再度XAMLを読み込んでIdを表示 var item2 = XamlReader.Load( typeof(Program).Assembly.GetManifestResourceStream("MarkupExtensionSample.Item.xaml")) as Item; Console.WriteLine(item2.Id); } } }
実行すると、Idの値が毎回ことなっていることが確認できます。
item-574cb4ed-4ec4-46ce-9e99-76f09b7545b7 item-d56c2d5e-f608-4ccc-8702-dffa18f366a9