F#でWPFやるときのTipsとか(その1)
最近、Full F#でWPFしてるので、Tipsてきなものをまとめようと思います。 その2はTipsがたまればあるかもしれませんが、過度な期待はしないでください。
プロジェクトの作り方
基本的には、Pure F# WPF GUIアプリ開発に向けてに書いてある通りです。 細かい注意点があるので書いておきます。
.NET Frameworkの選択に関する注意点
.NET Frameworkを4.5.1や4.5.2などのような3桁のものを選ぼうとすると、プロジェクト作成に失敗します。 また、4.6を選んでも4.5として作られるので、その点にも注意しましょう。
初回以外での作成
言うまでもないことかもしれませんが一応。 一回でも「F# Empty Windows App (WPF)」を使ってプロジェクトを作った場合、それ以降は「オンライン」の方ではなく、「インストール済み」のテンプレートを選ぶことになります。
MainView.xaml.fs
「F# Empty Windows App (WPF)」というテンプレートでプロジェクトを作ると、下記の内容でMainView.xaml.fsというファイルが生成されます。
namespace ViewModels open System open System.Windows open FSharp.ViewModule open FSharp.ViewModule.Validation open FsXaml type MainView = XAML<"MainWindow.xaml", true> type MainViewModel() as self = inherit ViewModelBase()
不要な型
実際にこのテンプレートで作る際、MVVMで作る場合は MainView
は不要です。
こいつはC#でのコードビハインドで作る場合に使うものに相当するため、MVVMで行く場合は消してしまって大丈夫です。
当然、C#でのコードビハインドで作る場合は MainViewModel
の方が不要なので、消してしまいましょう。
ただし、生成されるコードは完全にMVVMでやること前提なコードになっているので、正直お勧めしません。
細かいことですが、MainViewModel
の定義の =
の後ろに1つ、その下の行に4つ、空白文字が紛れ込んでいるのも注意しましょう。
気になる人は消してしまうといいでしょう。
App.fs
MainView.xaml.fs同様にテンプレートによって作られるファイルです。
module main open System open FsXaml open System.Windows type App = XAML<"App.xaml"> [<STAThread>] [<EntryPoint>] let main argv = App().Root.Run()
モジュール名
なぜか小文字で main
というモジュールになっています。
細かい部分ですが、Main
とか App
とかに変えたほうがいいでしょう。
XAML Type Providerについて
テンプレートで作られる構成がMVVMスタイルで作ることを意識したものになっていますので、あまりXAML Type Providerの出番はないのですが、Type Providerの使い方の例として触れておきます。
コード生成の代替としてのType Provider
C#でのコードビハインドではdesigner.csファイルが自動生成されますが、F#はXAML Type Providerの力によりそういったファイルは生成されません。
その代わりに、type HogeView = XAML<"xamlファイル名", true>
のようにしてビュー用の型をXAMLから生成することになります。
テンプレートによって生成されたプロジェクトを弄って、ちょっと使って見ましょう。
不要なファイルを消す
XAML Type Providerを使う場合は次のファイルは不要です。消してしまいましょう。
MainWindow.xamlを書き換える
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ViewModels;assembly=FsEmptyWindowsApp3" xmlns:fsxaml="http://github.com/fsprojects/FsXaml" Title="MVVM and XAML Type provider" Height="200" Width="400"> <Grid> <Label x:Name="Message"/> </Grid> </Window>
Message
という名前を持った Label
を追加しました。
App.fsを書き換える
App.fsを書き換え、先ほど追加したラベルにテキストを設定してみます。
module App open System open FsXaml open System.Windows type MainView = XAML<"MainWindow.xaml", true> [<STAThread>] [<EntryPoint>] let main argv = // XAML Type Providerによって生成された型のインスタンスを生成し、 let view = MainView() // Messageというプロパティにアクセスし、Contentに文字列を設定 view.Message.Content <- "Hello XAML Type Provider!" // Application.RunにXAMLのRoot要素であるWindowオブジェクトを渡して、 // アプリケーションを起動 let app = Application() app.Run(view.Root)
これでビルドして実行すると、「Hello XAML Type Provider!」と表示されたウィンドウが開きます。
XAML Type Providerの力によって、自動生成コードなしでビューにアクセスできました。
イベントの登録
これだけだと、全部XAMLに書けばいいじゃん、という話になってしまうので、ボタンを追加してボタンにイベントを登録してみましょう。
MainWindow.xamlの内容を変更します。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ViewModels;assembly=FsEmptyWindowsApp3" xmlns:fsxaml="http://github.com/fsprojects/FsXaml" Title="MVVM and XAML Type provider" Height="200" Width="400"> <StackPanel> <Label x:Name="Message"/> <Button x:Name="Btn">Please Click!</Button> </StackPanel> </Window>
Grid
は面倒なので StackPanel
に変え、Label
の下に Btn
という名前でボタンを追加しました。
そして、app.Run(view.Root)
の前にイベントを追加するコードを書きます。
view.Btn.Click.Add(fun x -> view.Message.Content <- "Clicked!")
これをビルドして実行すると、先ほど作った画面にボタンが追加されたウィンドウが開きます。 そして、ボタンをクリックするとラベルの内容が変わります。
こんな感じで、画面の要素に名前を付けておけば、かなり簡単に画面が作れることが分かります。 まぁ、ちょっとした画面であればXAML Type Providerも選択肢に入れてもいいかな、という感じでしょうか。