Elmish.WPFでオブジェクトのリストを雑にグリッドビューに流し込む


- 意図
	- Elmish.WPFを使用する
	- C#を使わずF#だけで完結させる
    	- XAMLを埋め込みリソースとして保持して実行時にロードする
	- query式で出力を加工し、オブジェクトのプロパティをそのままカラムとして使用する

- 備忘
    - XAMLまったく分からない
	- XAMLのデータバインディングを忘れても警告も何も出ないので注意する
	- F#のオブジェクトのリスト(のようなもの全般)はqueryのおかげで実質テーブル
	- `dotnet publish -c Release` でシングルバイナリ(160MB)を出力するようにfsprojを設定してある
		- SelfContained=falseにすればフレームワーク依存の実行ファイルができる(4MB)


```wpf3.fsproj
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>net7.0-windows</TargetFramework>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <UseWpf>true</UseWpf>
     <OutputType>WinExe</OutputType>
 
     <SelfContained>true</SelfContained>
    
     <PublishSingleFile>true</PublishSingleFile>
     <RuntimeIdentifier>win-x64</RuntimeIdentifier>
     <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
 
   </PropertyGroup>
 
   <ItemGroup>
     <PackageReference Include="Elmish.WPF" Version="3.5.8" />
   </ItemGroup>
   
   <ItemGroup>
     <Resource Include="MainWindow.xaml" />
     <Compile Include="Library.fs" />
   </ItemGroup>
   
 </Project>
```

```Library.fs
 module MainWindow
 
 module hoge =
     open System.IO
 
     let hoge1 () = // グリッドビューに表示したいオブジェクトのseqを得る関数
         let desktop =
             System.Environment.GetFolderPath System.Environment.SpecialFolder.DesktopDirectory
 
         let files =
             System.IO.Directory.EnumerateFiles(desktop, "*.txt", EnumerationOptions(RecurseSubdirectories = false))
             |> Seq.map (fun path -> FileInfo path)
 
         query {
             for file in files do
                 select
                     {| name = file.Name
                        size = file.Length |}
         }
         |> Seq.cast<obj>
 
 
 module gui =
     open Elmish.WPF
 
     type Model = { GridItemList: obj seq }
 
     type Msg =
         | Load
         | Reset
 
     let init = { GridItemList = [] }
 
     let canReset = (<>) init
 
     let update msg m =
         match msg with
         | Load -> { m with GridItemList = hoge.hoge1 () }
         | Reset -> init
 
     let bindings () : Elmish.WPF.Binding<Model, Msg> list =
         [ "Load" |> Binding.cmd Load
           "Reset" |> Binding.cmdIf (Reset, canReset)
           "GridItemList" |> Binding.oneWay (fun m -> m.GridItemList) ]
 
     let designVm = Elmish.WPF.ViewModel.designInstance init (bindings ())
 
 
     let main window =
         Elmish.WPF.Program.mkSimpleWpf (fun () -> init) update bindings
         |> Program.runWindow window
 
 
 open System.Windows.Markup
 open System.Windows.Controls
 open System.Windows
 
 
 [<EntryPoint; System.STAThreadAttribute>]
 let entryPoint args =
     let uri = new System.Uri(@"/MainWindow.xaml", System.UriKind.Relative)
     let stream = Application.GetResourceStream(uri).Stream
     let window = XamlReader.Load(stream) :?> System.Windows.Window
     gui.main window
```

```MainWindow.xaml
 <Window x:Class="System.Windows.Window"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:vm="clr-namespace:Elmish.WPF.Samples.SingleCounter;assembly=SingleCounter.Core"
         Title="Sample"
         Height="200"
         Width="500"
         WindowStartupLocation="CenterScreen"
         mc:Ignorable="d"
         d:DataContext="{x:Static vm:Program.designVm}">
 
 
 <Grid>
     <Grid.RowDefinitions>
         <RowDefinition Height="32" />  
         <RowDefinition Height="*" />  
     </Grid.RowDefinitions>
 
     <StackPanel Grid.Row="0"  Orientation="Horizontal">
         <Button Width="80" Margin="5,5,10,5" Content="Load" Command="{Binding Load}" />
         <Button Width="80" Margin="0,5,10,5" Content="Reset" Command="{Binding Reset}" />
     </StackPanel>
 
     <DataGrid Grid.Row="1" x:Name="DataGrid1"
         Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
         ItemsSource="{Binding GridItemList, Mode=OneWay}"
         AutoGenerateColumns="true"
         IsReadOnly="true" >
     </DataGrid>
 
 </Grid>
 
 </Window>
```