F#でWPFやるときのTipsとか(その2)
F#でWPFやるときのTipsとか(その1)の続編です。
添付プロパティの作り方
F#で添付プロパティを作るには、添付プロパティの本体はプロパティではなくフィールドに保持する必要があるようです。
// ダメな例 type Sample private () = static member SomeValueProperty = DependencyProperty.RegisterAttached("SomeValue", typeof<string>, typeof<Sample>, FrameworkPropertyMetaData("", Sample.OnSomeValueChanged)) static member GetSomeValue(obj: DependencyObject) = obj.GetValue(Sample.SomeValueProperty) :?> string static member SetSomeValue(obj: DependencyObject, value: string) = obj.SetValue(Sample.SomeValueProperty, value) static member OnSomeValueChanged = PropertyChangedCallback(fun sender e -> // プロパティが変更されたときの処理 )
このコードはコンパイルは通りますが、この添付プロパティにXAML内でBindingしようとすると、
'Button' コレクション内で 'Binding' を使用することはできません。'Binding' は、DependencyObject の DependencyProperty でのみ設定できます。
というエラーになってしまいます。
プロパティではなくフィールドを使うとうまくいきます。
type Sample private () = // 一旦staticなフィールドに保持しておいて、 static let someValueProperty = DependencyProperty.RegisterAttached("SomeValue", typeof<string>, typeof<Sample>, FrameworkPropertyMetaData("", Sample.OnSomeValueChanged)) // プロパティの値として保持したフィールドを設定 static member SomeValueProperty = someValueProperty static member GetSomeValue(obj: DependencyObject) = obj.GetValue(Sample.SomeValueProperty) :?> string static member SetSomeValue(obj: DependencyObject, value: string) = obj.SetValue(Sample.SomeValueProperty, value) static member OnSomeValueChanged = PropertyChangedCallback(fun sender e -> // プロパティが変更されたときの処理 )
添付プロパティがF#で書けるため、WPFのかなりの部分がF#のみで完結できると思われます。 Full F#でWPFがかなり現実味を帯びてきました。 足りないのは各種ユーティリティなので、その辺の再実装が苦でない人であれば、十分選択肢に入ってくる環境はすでに整ったと言えるでしょう。
別Windowの開き方
今のところ、一番手軽に別Windowを開くには、XAML Type Providerを使うのがいいでしょう。
まずはXAMLを作る必要がありますが、F#のプロジェクトではXAMLのアイテムテンプレートがないため、「General」の「XMLファイル」を選んでファイルの拡張子をxamlに変更します。 注意点として、この方法で追加したファイルは「ビルドアクション」が「None」になっているので、「Resource」に変更しておく必要があります。
「F# Empty Windows App (WPF)」テンプレートでプロジェクトを作った場合、
type OtherView = XAML<"OtherWindow.xaml">
としてViewを表す型を作っておいて、何らかのコマンド内でこの型のオブジェクトを生成して Show
(もしくは ShowDialog
)を呼び出します。
member this.OnClick = this.Factory.CommandSync (fun () -> let view = OtherView() view.Root.Show() )
ちなみに、「F# Empty Windows App (WPF)」テンプレートで導入されるFsXaml.Wpfは古い(0.9.9)ため、パッケージを更新(現時点では2.1.0)するとビルドが通らなくなります。
ビルドを通すためには、Root
プロパティへのアクセスを消してください。
member this.OnClick = this.Factory.CommandSync (fun () -> let view = OtherView() view.Show() )
App.fsもコンパイルエラーになるので、そちらの Root
も削除しましょう。
[<STAThread>] [<EntryPoint>] let main argv = App().Run()