F#でWPF --- XAMLデザイナでサンプルデータ利用
VisualStudioに備え付けのXAMLエディタでデザインをする際、実行時に決定される可変個のコントロールを扱うのは大変です。
そこで今回は、デザイン時にサンプルのViewModelを利用する方法を書いていきます。
DesignInstance
下記のようにXAMLを記述することにより、デザインビュー上のDataContextにインスタンスを設定できます。
ここではnamespace SamplesにあるSampleVMクラスを参照しています。
尚、DesignInstanceに指定する型は、引数なしコンストラクタを公開している必要があります。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:Samples;assembly=DesignTimeSample" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DataContext="{d:DesignInstance local:SampleVM, IsDesignTimeCreatable=True}"> </Window>
レコードからサンプルViewModelの自動生成
F#のレコードには引数なしコンストラクタがありません。
そこでレコードと同じプロパティを持ち、引数なしコンストラクタを持つクラスを作ります。
今回はDynamicObjectを用いて自動的にクラスを作成するようにします。
open System.Dynamic open System.Runtime.InteropServices [<AbstractClass>] type DesignTimeViewModel(instance : obj) = inherit DynamicObject() let properties = instance.GetType().GetProperties() |> Array.map (fun x -> x.Name, x) |> dict override this.TryGetMember(binder : GetMemberBinder, [<Out>] result : obj byref) = result <- properties.Item(binder.Name).GetValue(instance) true
DesignInstanceなし
DesignInstanceなしの場合、Bindingの中身が実行時にならないとわからないため、デザイナには何も表示されません。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Title="MainWindow" Height="130" Width="130"> <Grid> <TextBlock Text="{Binding Text}" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/> <Polyline Margin="0,30,0,0" Points="{Binding Points}" Stroke="Red" StrokeThickness="10" /> </Grid> </Window>
type ViewModel = { Text : string Points : PointCollection }
DesignInstance利用
デザイナにSampleVMの内容が反映されていることが確認できます。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:Samples;assembly=DesignTimeViewModel" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DataContext="{d:DesignInstance local:SampleVM, IsDesignTimeCreatable=True}" Title="MainWindow" Height="130" Width="130"> <Grid> <TextBlock Text="{Binding Text}" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/> <Polyline Margin="0,30,0,0" Points="{Binding Points}" Stroke="Red" StrokeThickness="10" /> </Grid> </Window>
namespace Samples type SampleVM() = inherit DesignTimeViewModel( { Text = "Hello" Points = [ Point(10.0, 40.0) Point(60.0, 10.0) Point(40.0, 50.0) Point(100.0, 10.0) ] |> PointCollection })
XAMLデザイナのインテリセンス
現時点において(Visual Studio 2015 Update 3)XAMLでインテリセンスがサポートされています。
例えばBinding記述時に、DesignInstanceに設定したクラスのプロパティが候補に出てきます。
しかし今回はDynamicObjectを利用しているため、このインテリセンスは利用できません。
TypeProvidersを利用すると解決できるかもしれません。