F#でWPF --- ファイルダイアログCommand

今回はファイルダイアログを開いて選択されたパスをCommandで送る機能を実装します。

この機能を実装するにあたり、Actionを利用します。

Action

Behaviorと同じく、System.Windows.Interactivity.dllを利用します。

Behaviorの詳細は下記記事を参照してください。
F#でWPF --- チェックボックスCommand --- Behavior利用 - 何でもプログラミング

ActionはTriggerと共に用いられ、例えばボタンがクリックされた時にCommandを実行する記述は下記の様になります。(挙動はButtonのCommandを利用するのと同じです。)

<Button>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:InvokeCommandAction Command="{Binding DoSomething}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>


OpenFileDialogAction

独自のActionを作成するには、TriggerActionを継承しInvoke関数をオーバーライドします。

open System.Windows
open System.Windows.Input
open System.Windows.Interactivity
open Microsoft.FSharp.Linq.NullableOperators
open Microsoft.Win32

type OpenFileDialogAction() = 
    inherit TriggerAction<FrameworkElement>()
    static member val CommandProperty = DependencyProperty.Register("Command", typeof<ICommand>, typeof<OpenFileDialogAction>)
    member this.Command with get()           = this.GetValue(OpenFileDialogAction.CommandProperty) :?> ICommand
                        and  set(x:ICommand) = this.SetValue(OpenFileDialogAction.CommandProperty, x)

    static member val FilterProperty = DependencyProperty.Register("Filter", typeof<string>, typeof<OpenFileDialogAction>)
    member this.Filter with get()         = this.GetValue(OpenFileDialogAction.FilterProperty) :?> string
                        and set(x:string) = this.SetValue(OpenFileDialogAction.FilterProperty, x)

    override this.Invoke parameter = 
        let dialog = OpenFileDialog(Filter = this.Filter)
        if dialog.ShowDialog() ?= true && this.Command <> null then 
            this.Command.Execute dialog.FileName


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

ボタンを押してファイルダイアログを開き、パスを選択するとテキストボックスにパスが表示されるアプリケーションを作成します。
f:id:any-programming:20170205225741p:plain

アプリケーションコード

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

OpenFileDialogActionはnamespace Actionsに定義されています。

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

またF#でWPFプロジェクトを作成する方法は下記記事を参照してください。
F#でWPF --- ウィンドウ表示 - 何でもプログラミング

Xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
        xmlns:local="clr-namespace:Actions;assembly=Actions"
        Title="MainWindow" Height="80" Width="250">
    <Grid>
        <Button Content="ファイルダイアログ" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="100">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <local:OpenFileDialogAction Command="{Binding SetPath}" Filter="F#|*.fs" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <TextBlock Text="{Binding Path}" HorizontalAlignment="Left" Margin="115,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top"/>
    </Grid>
</Window>

F#

open System
open System.Windows

type Model = { Path : string }

type Msg = SetPath of string

let updateModel model msg =
    match msg with
    | SetPath x -> 
        { model with Path = x }

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