Skip to content

Instantly share code, notes, and snippets.

@JordanMarr
Last active January 16, 2022 16:28
Show Gist options
  • Save JordanMarr/b578a1f389d32c4c5b4c5d83717d1711 to your computer and use it in GitHub Desktop.
Save JordanMarr/b578a1f389d32c4c5b4c5d83717d1711 to your computer and use it in GitHub Desktop.
Example of Using Elmish.WPF + Rx
<Window x:Class="ConsoleApp.Wpf.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ConsoleApp.Wpf.Views"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="0,25,0,0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock Text="{Binding CounterValue, StringFormat='Counter value: {0}'}" Width="110" Margin="0,5,10,5" />
<Button Command="{Binding Decrement}" Content="-" Margin="0,5,10,5" Width="30" />
<Button Command="{Binding Increment}" Content="+" Margin="0,5,10,5" Width="30" />
<TextBlock Text="{Binding StepSize, StringFormat='Step size: {0}'}" Width="70" Margin="0,5,10,5" />
<Slider Value="{Binding StepSize}" TickFrequency="1" Maximum="10" Minimum="1" IsSnapToTickEnabled="True" Width="100" Margin="0,5,10,5" />
<Button Command="{Binding Reset}" Content="Reset" Margin="0,5,10,5" Width="50" />
</StackPanel>
</Grid>
</Window>
module ConsoleApp.Wpf.Program
open System
open ConsoleApp.Wpf.Views
open Elmish
open Elmish.WPF
open System.Reactive.Subjects
open System.Reactive.Linq
type Model =
{ Count: int
StepSize: int
StepSizeChanged: Subject<int> }
let init () =
{ Count = 0
StepSize = 1
StepSizeChanged = new Subject<int>() }
type Msg =
| Increment
| Decrement
| SetStepSize of int
| Reset
| WaitForRx
let update msg m =
match msg with
| Increment -> { m with Count = m.Count + m.StepSize }
| Decrement -> { m with Count = m.Count - m.StepSize }
| SetStepSize x -> { m with StepSize = x }
| Reset -> { init() with StepSizeChanged = m.StepSizeChanged }
| WaitForRx -> m
let bindings model dispatch =
[
"CounterValue" |> Binding.oneWay (fun m -> m.Count)
"Increment" |> Binding.cmd (fun m -> Increment)
"Decrement" |> Binding.cmd (fun m -> Decrement)
"Reset" |> Binding.cmdIf (fun _ -> Reset) (fun m -> m <> init ())
"StepSize" |> Binding.twoWay
(fun m -> float m.StepSize)
//(fun v m -> int v |> SetStepSize) // Pre-Rx setter -- see below
(fun v m ->
m.StepSizeChanged.OnNext (int v)
WaitForRx
)
]
let rxSubcription initialModel =
Cmd.ofSub (fun dispatch ->
// Subscribe to observable
initialModel.StepSizeChanged
.Throttle(TimeSpan.FromMilliseconds(500.0))
.DistinctUntilChanged()
.Subscribe(fun size ->
dispatch (size |> SetStepSize)
) |> ignore
initialModel.StepSizeChanged.OnNext(1) // Optional: "Prime the Pump" - set it to the default value of 1
)
[<EntryPoint; STAThread>]
let main argv =
Program.mkSimple init update bindings
|> Program.withSubscription rxSubcription
|> Program.withConsoleTrace
|> Program.runWindowWithConfig
{ ElmConfig.Default with LogConsole = true }
(MainWindow())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment