こんにちは、ゆたんぽです。
今回は改善報告で紹介したModelからView、ViewModelへの自動展開を紹介していこうと思います。
今回実装するのは、画像処理で必要なパラメータをModel側の情報をもとにして、Viewへ展開していく仕組みです。
下のようにHambergerMenuのボタンを押すとパラメータ部分が切り替わっているのがわかると思います。
これは、1つ1つの画像処理にViewを用意するのではなく、1つTemplateを作成してそれをリスト型にして並べて表示しています。
そのため、Viewを何度も作る必要がなく、追加したいパラメータをModel側で定義したクラスの中に追加するだけで反映できるようになります。
これらの実装の説明は長くなりますので3部構成でView、Model、ViewModelの順に説明していきます。
今回はViewから紹介していきます。
Viewの構想
まず、実装の中身を紹介する前に考え方について説明します。
下の図のように画像処理のパラメータはthreshold(閾値)やmaxVal(最大値)など値を入力するために使用されます。
これらのパラメータはNameとValueという共通点があり、それらをテンプレート化するとテンプレートを並べるだけでパラメータのViewの役割は満たすことができます。
そのため、下図にあるようにName+Valueというテンプレートを作ることがViewで行うことになります。
NameとValueの紐づけなどはViewModel編で実装していきますのでまずはテンプレートを作成していきましょう。
テンプレートView作成
上記Viewの構想で説明したテンプレートのViewを作成します。
今回は色々な値に対応できるようにDecimal型のテンプレートを作成していきます。
まず、「ParamDecimal」というViewを作成してください。
PrismのView作成時にViewModelを同時に作成しても構いません。
<UserControl x:Class="OpenCV_Prism.Views.ParamDecimal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
prism:ViewModelLocator.AutoWireViewModel="False">
<Grid>
<Border>
<StackPanel Margin="5" Orientation="Horizontal" >
<TextBlock Text="{Binding ParamName.Value}" HorizontalAlignment="Left" Width="100" FontSize="20" Margin="5"/>
<mah:NumericUpDown x:Name="Threshold"
BorderThickness="1"
Width="150"
HorizontalAlignment="Left"
Minimum="{Binding Min.Value}"
Maximum="{Binding Max.Value}"
Interval="{Binding Inter.Value}"
HorizontalContentAlignment="Left"
FontSize="20"
StringFormat="{Binding StringFormat.Value}"
Value="{Binding ConstValue.Value, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</Border>
</Grid>
</UserControl>
NameとValueを表示するViewのxamlファイルになります。
上記のようにStackPanel型でNameとValueを横並びにしています。
テンプレートを作成する方法は今までのViewを作成する方法と同様です。
値はModel側まで通知する必要があるのでReactivePropertyを使用するために”.Value”を使用してデータバインディングを行います。
データバインディングを行う項目は、Name部分はParamNameのみです。
一方、Value部分は多くデータバインディングを行っています。
これには理由があって、今回実装しているNumericUpDownでは値だけでなく、最小値や最大値、初期値、間隔、表示のフォーマットなどを決める必要がありからです。
これらの項目はパラメータ毎に異なるため、Model側で情報を書き込んだ内容をそのまま反映させる必要があります。
各項目の説明は以前のNumericUpDownの記事で紹介していますので詳細はそちらをご覧ください。
テンプレートViewをリスト型で表示(ParamDisplay)
次に上記で作成したParamDecimalをリスト型で表示するViewを作成していきます。
先ほどと同様にViewを作成して、「ParamDisplay」という名前にしてください。
<UserControl x:Class="OpenCV_Prism.Views.ParamDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:views="clr-namespace:OpenCV_Prism.Views"
xmlns:viewmodels="clr-namespace:OpenCV_Prism.ViewModels"
xmlns:dj="clr-namespace:OpenCV_Prism.DataTemplateSelectors"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="dtPrmDecimal">
<views:ParamDecimal Margin="0 0 3 6"/>
</DataTemplate>
</Grid.Resources>
<Border BorderThickness="1" BorderBrush="Black">
<ItemsControl ItemsSource="{Binding ItemsSource}">
<ItemsControl.ItemTemplateSelector>
<dj:ParamTypeDataTemplateSelector DtPrmDecimal="{StaticResource dtPrmDecimal} />
</ItemsControl.ItemTemplateSelector>
</ItemsControl>
</Border>
</Grid>
</UserControl>
上記のコードを説明していきます。
GridResourcesはHambergerMenuで説明したWindowsResourcesと同じです。
Gridで利用するためGridという名前の違いがあるだけです。
DataTemplateは”x:Key”を使用してキーワードでViewの設定を呼び出すことができます。
そのため、上記の記述は”dtPrmDecimal”というキーを使用して、先ほど作成したParamDecimalというViewを呼び出すことができるという意味です。
views:部分では、ParamDecimalを呼び出すためのアドレスですので自分がViewを作成したアドレスを設定するようにしましょう。
次に、ItemControlはHambergerMenuと同様にItemSourcesを設定することができます。
ItemSourcesでは、先ほど作成したViewのリストを指定することができます。
ここでは、“ItemsSource”という名前でデータバインディングを行っています。
ViewModel側でItemsSourceに紐づくデータのリストを追加することで、Viewなどを作成せずに簡単に繰り返しのViewを表示することができます。
簡単に説明すると一つのViewのリストだけでなく、様々な形のViewをリストとして表示することができるようになります。
そのため、事前にViewを振り分けるクラスを作成して、ItemSourcesに入れるViewの情報からViewの種類を判定できるようにしていきます。
詳しくは、次回のModel編で説明していきます。
まとめ&次回予告
今回は改善報告で紹介したModelからView、ViewModelへの自動展開を紹介していく中で、まずViewを作成していきました。
ViewができればModelを作成して、ViewModelへの展開ができるようになります。
次回は、Model側の実装を記事にしていきますのでよろしくお願いします。