WPFでF#も使いたい!
はじめに
F#には現状、WPFを扱うテンプレートが存在しておらず、デフォルトの状態ではWPFでF#を用いるのは難しいですが、今回F#のみでウィンドウの表示に成功している例を見つけることができたので共有したいと思います。
参考:https://github.com/kalugvasy3/How-to-create-WPF-application-with-F-sharp-only-with-Dot-Net-Core-3.1
プロジェクトファイル(fsproj)
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Page Remove="MainWindow.xaml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="MainWindow.xaml" />
<Compile Include="MainWindow.fs" />
</ItemGroup>
</Project>
WPFのcsprojと異なるのは、埋め込みリソースとしてMainWindow.xamlを含める必要があります。
MainWindow.fs
open System
open System.Windows
open System.Windows.Markup
open System.Reflection
[<STAThread>]
[<EntryPoint>]
do Assembly.GetExecutingAssembly().GetManifestResourceNames()
|> Array.find(fun x -> x.Contains("MainWindow.xaml"))
|> Assembly.GetExecutingAssembly().GetManifestResourceStream
|> XamlReader.Load :?> Window
|> Application().Run |> ignore
現在実行中のアセンブリをGetExecutingAssembly
メソッドで取得し、さらにGetManifestResourceNames
でリソース名称が格納された文字列配列を取得します。その中からMainWindow.xamlの文字列を含む要素をfind
関数で取得します。見つからない可能性も加味してoption型で返すtryFind
関数を使った方がいいかもしれません。
そして、取得したリソース名を使ってリソースのStream
を取得し、Stream
(つまりXamlファイルの内容)からXamlReader.Load
メソッドを使ってオブジェクトを生成しています。Load
メソッドからの戻り値はObject
型(F#ではobj
)なので:?>
演算子でSystem.Windows.Window
型へダウンキャストを行っています。
MainWindow.xaml
特に通常と変わりない記述で問題ありません。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MinWidth="450" MinHeight="266" Title="I want to use Windows Presentation Foundation with F#!" SizeToContent="WidthAndHeight">
<Grid x:Name="gridAll" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5" >
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Hello F#!" />
</Grid>
</Window>
実行
備考
ホットリロードはどうやら動かないみたいです。
Visual StudioのデザイナーはC#と同様に使用することができます。
終わりに
このままだとF#でWPFをやる!という時に逐一プロジェクトファイルなどを書き換える必要があるので、こちらのチュートリアルなどを参考にテンプレートを作ると便利です。
備考
GitHubのIssueにもサポートを望む声が少しあるようです。
また、ElmというJavaScriptにコンパイル可能な関数型言語のF#実装である、ElmishというライブラリがF#には存在していて、ElmishでWPFを書くElmish.WPFがあるので、こちらもいずれ試してみたいと思います。
Discussion
この記事の通りの手順で、F#のUWPアプリが作れました!ありがとうございます!