elmish-wpf

Elmish.WPF - binding collection to multiple instances of a window


The sample NewWindow (https://github.com/elmish/Elmish.WPF/tree/master/src/Samples), shows how to open new windows and bind the DataContext to the application model.

Given a model

//App.fs
type Model =
  { Window1Data: Window1Model
    ...}

a button

//MainWindow.xaml
...
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
  <Button Command="{Binding Window1Show}"  Content="Show"  Width="70" Margin="5" />

a binding associated to the button and one to the type of the Window to be open (Window1)

//App.fs

  let bindings (createWindow1: unit -> #Window) (createWindow2: unit -> #Window) () = [
    "Window1Show" |> Binding.cmd Window1Show
    ...
    "Window1" |> Binding.subModelWin(
      (fun m -> WindowState.set m.Window1Data),
      snd,
      id,
      Window1.bindings >> Bindings.mapMsg Window1SetInput,
      createWindow1)
    ...

when I click on the button the window opens with the correct binding.

I need to make this parametric. For example, let's suppose I have a collection:

//App.fs
type Model =
  { Window1Data: Window1Model list
    ...}

multiple buttons bound to the command with parameter:


//MainWindow.xaml
...
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
  <Button Command="{Binding Window1Show}" CommandParameter="1" Content="Show"  Width="70" Margin="5" />
  <Button Command="{Binding Window1Show}" CommandParameter="2" Content="Show"  Width="70" Margin="5" />
...
  <Button Command="{Binding Window1Show}" CommandParameter="N" Content="Show"  Width="70" Margin="5" />

When I click on any button, a new instance of Window1 should open, bound to the corresponding item in the collection in the model. For example, if I click the second button (CommandParameter="2"), a new Window1 instance should open, bound to Model.Window1Data[2].

I cannot figure out how to write the bindings for this.

I guess it should be some something like:

//App.fs

  let bindings (createWindow1: unit -> #Window) (createWindow2: unit -> #Window) () = [
    "Window1Show" |> Binding.cmdParam (int >> Window1Show)
    ...
    "Window1" |> Binding.subModelWinParam(
      (fun p m -> WindowState.set m.Window1Data[p]),
      snd,
      id,
      Window1.bindings >> Bindings.mapMsg Window1SetInput,
      createWindow1)
    ...

but there is not a subModelWinParam in Elmish.WPF.


Solution

  • If you truly have a constant number N of buttons in a stack panel, then have each use a unique binding:

    //MainWindow.xaml
    ...
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
      <Button Command="{Binding Window1Show1}" Content="Show"  Width="70" Margin="5" />
      <Button Command="{Binding Window1Show2}" Content="Show"  Width="70" Margin="5" />
    ...
      <Button Command="{Binding Window1ShowN}" Content="Show"  Width="70" Margin="5" />
    

    If you have a variable number of buttons, then you must be using a SubModelSeq binding. Then each of those submodels should have one button and one SubModelWin binding.