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

F#でWPF --- 可変個のコントロール --- 型で生成するコントロールを変更

F# MVVM WPF

下記記事では同じ型のリストを元にコントロールを作成しました。
F#でWPF --- 可変個のコントロール - 何でもプログラミング

今回は異なる型のリスト(ベースクラスのリストで、各インスタンスの型はバラバラ)を元にコントロールを作成してみます。

作成するアプリケーション

追加ボタンを押すと、円か正方形がランダムに追加されるアプリケーションを作成します。

f:id:any-programming:20170212093152p:plain

Xaml基本フォーマット

Resourcesの中にDataTemplateを複数用意します。

DataTypeに対象の型を指定することにより関連付けされます。

<ItemsControl ItemsSource="{Binding Data}" >
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type MyType1}">
            <!-- Control1 -->
        </DataTemplate>
        <DataTemplate DataType="{x:Type MyType2}">
            <!-- Control1 -->
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>


コード全体

Shapeの定義に判別共用体を使いたいのですが、DataTemplateのDataTypeで認識されません。

そのため純粋なクラスの継承で記述してあります。

判別共用体でうまくDataTypeに指定できる方法が見つかりましたらまた記事にしたいと思います。

Program.fsで利用しているDataContextは下記記事を参照してください。
F#でWPF --- Elm Architectureを利用したMVVM - 何でもプログラミング

アプリケーション名はShapes.exeです。

Shapes.fs

namespace Shapes

open System.Windows

[<AbstractClass>]
type Shape(position : Point) =
    member this.Position = position

type Circle(position : Point) =
    inherit Shape(position)

type Rectangle(position : Point) =
    inherit Shape(position)

Program.fs

open System
open Shapes

type Msg = AddShape

type Model = { Shapes : Shape list }

let initialModel = { Shapes = [] }

let random = Random()

let updateModel model msg =
    let p = Windows.Point(random.Next(100) |> double, random.Next(100) |> double)
    match msg with
    | AddShape ->
        let shape = match random.Next(2) with
                    | 1 -> Circle(p)    :> Shape
                    | _ -> Rectangle(p) :> Shape
        { model with Shapes = shape :: model.Shapes }

open System.Windows

[<STAThread>]
[<EntryPoint>]
let main argv = 
    let window = Application.LoadComponent(Uri("MainWindow.xaml", UriKind.Relative)) :?> Window
    window.DataContext <- DataContext(initialModel, updateModel, id)
    Application().Run(window) |> ignore
    0

Xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Shapes;assembly=Shapes"
        Title="MainWindow" Height="180" Width="140">
    <Grid>
        <ItemsControl ItemsSource="{Binding Shapes}" Width="100" Height="100" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type local:Circle}">
                    <Ellipse Width="15" Height="15" Fill="Orange" />
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:Rectangle}">
                    <Rectangle Width="15" Height="15" Fill="Orange" />
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Canvas.Left" Value="{Binding Position.X}" />
                    <Setter Property="Canvas.Top"  Value="{Binding Position.Y}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>
        <Button Content="追加" Command="{Binding AddShape}" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>