読者です 読者をやめる 読者になる 読者になる

SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

マークアップ拡張を作って、XAMLでグラデーションを簡単に書く方法

マークアップ拡張って、結構便利!!
マークアップ拡張は初めて作ってみたけど、覚えておくと結構便利かも。

マークアップ拡張については、以下のリンクが参考になりました。
http://okazuki.hatenablog.com/entry/20130103/1357205143
http://d.hatena.ne.jp/kazutoex/20100427/1272373197
http://10rem.net/blog/2011/03/09/creating-a-custom-markup-extension-in-wpf-and-soon-silverlight
http://blogs.msdn.com/b/mikehillberg/archive/2008/04/24/simple-way-to-create-a-gradient-brush-in-xaml.aspx

マークアップ拡張を作る手順

  1. マークアップ拡張用のクラスを作る
  2. クラス名は○○Extensionにする
  3. MarkupExtensionクラスを継承する
  4. ProvideValueメソッドをオーバーライド

使い方も簡単で、IValueConverterなんかと同じように、
マークアップ拡張を書いた名前空間XAMLに定義しておくと使えるようになります。

LinearGradientBrushを簡単に生成するマークアップ拡張

で、このマークアップ拡張って、どんな時に便利なの?って話です。
XAMLでは任意のCLRオブジェクトをXMLのツリー構造として表現できますが、複雑な入れ子構造を持ったオブジェクトをXML形式で書くのは結構面倒です。
そんな時にマークアップ拡張を作ると、目的のオブジェクトを簡単に生成する手段を提供することができます。

たとえば、LinearGradientBrushなんかも、XAMLで書くのが面倒なものだと思います。
これを、マークアップ拡張で簡単に書けるようにしている記事があったので、自分でもやってみました。
http://blogs.msdn.com/b/mikehillberg/archive/2008/04/24/simple-way-to-create-a-gradient-brush-in-xaml.aspx


f:id:minami_SC:20140222232143p:plain
こういうグラデーションを作りたい時、
XAMLで普通にグラデーションを書こうとすると、↓みたいな記述になります。

        <Rectangle Width="300"
                   Height="200"
                   Margin="50"
                   Stroke="Black">
            <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Red" />
                    <GradientStop Offset="1" Color="White" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

複雑なグラデーションとかも記述できる書式なんですが、シンプルなグラデーションをパッと作るには、仰々しい感じがしますよね。

で、こんなマークアップ拡張を作っておくと、

    [MarkupExtensionReturnType(typeof(LinearGradientBrush))]
    public class LinearGradientBrushExtension : MarkupExtension
    {
        public LinearGradientBrushExtension()
        {
            StartColor = Colors.White;
            EndColor = Colors.Gray;
            Angle = 0;
        }

        public LinearGradientBrushExtension(Color startColor, Color endColor, double angle)
        {
            StartColor = startColor;
            EndColor = endColor;
            Angle = angle;
        }

        public Color StartColor { get; set; }
        public Color EndColor { get; set; }
        public double Angle { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return new LinearGradientBrushExtension(StartColor, EndColor, Angle);
        }
    }


こんなにシンプルに書けるようになります。

        <Rectangle Width="300"
                   Height="200"
                   Margin="50"
                   Fill="{local:LinearGradientBrush StartColor=Red,
                                                    EndColor=White,
                                                    Angle=90}"
                   Stroke="Black" />

コンバーターほどは、自分で作る機会はないと思いますが、
マークアップ拡張を自分で作れるようになってると、何かと便利な気がします。