Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Samples] from dynamic bindings to static VM ("SubModelOpt" sample) #607

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 155 additions & 93 deletions src/Samples/SubModelOpt.Core/Program.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Elmish.WPF.Samples.SubModelOpt.Program
namespace Program

open Serilog
open Serilog.Extensions.Logging
Expand All @@ -7,128 +7,190 @@ open Elmish.WPF

module Form1 =

type Model =
{ Text: string }
type Model = { Text: string }

type Msg =
| SetText of string
| Submit
type Msg =
| SetText of string
| Submit

let init =
{ Text = "" }
let init = { Text = "" }

let update msg m =
match msg with
| SetText s -> { m with Text = s }
| Submit -> m // handled by parent
let update msg m =
match msg with
| SetText s -> { m with Text = s }
| Submit -> m // handled by parent


[<AllowNullLiteral>]
type Form1_ViewModel(args) =
inherit ViewModelBase<Form1.Model, Form1.Msg>(args)

let text_Binding =
Binding.TwoWayT.id
>> Binding.mapModel (fun (m: Form1.Model) -> m.Text)
>> Binding.mapMsg Form1.SetText


member _.Text
with get() = base.Get() (text_Binding)
and set(v) = base.Set(v) (text_Binding)

member _.Submit = base.Get () (Binding.CmdT.setAlways Form1.Submit)

let bindings () : Binding<Model, Msg> list = [
"Text" |> Binding.twoWay ((fun m -> m.Text), SetText)
"Submit" |> Binding.cmd Submit
]


module Form2 =

type Model =
{ Text1: string
Text2: string }
type Model = { Text1: string; Text2: string }

type Msg =
| SetText1 of string
| SetText2 of string
| Submit

let init = { Text1 = ""; Text2 = "" }

let update msg m =
match msg with
| SetText1 s -> { m with Text1 = s }
| SetText2 s -> { m with Text2 = s }
| Submit -> m // handled by parent


[<AllowNullLiteral>]
type Form2_ViewModel(args) =
inherit ViewModelBase<Form2.Model, Form2.Msg>(args)

let text1_Binding =
Binding.TwoWayT.id
>> Binding.mapModel (fun (m: Form2.Model) -> m.Text1)
>> Binding.mapMsg Form2.SetText1

let text2_Binding =
Binding.TwoWayT.id
>> Binding.mapModel (fun (m: Form2.Model) -> m.Text2)
>> Binding.mapMsg Form2.SetText2

type Msg =
| SetText1 of string
| SetText2 of string
| Submit

let init =
{ Text1 = ""
Text2 = "" }
member _.Text1
with get () = base.Get () (text1_Binding)
and set (v) = base.Set (v) (text1_Binding)

let update msg m =
match msg with
| SetText1 s -> { m with Text1 = s }
| SetText2 s -> { m with Text2 = s }
| Submit -> m // handled by parent
member _.Text2
with get () = base.Get () (text2_Binding)
and set (v) = base.Set (v) (text2_Binding)

member _.Submit = base.Get () (Binding.CmdT.setAlways Form2.Submit)

let bindings () : Binding<Model, Msg> list = [
"Text1" |> Binding.twoWay ((fun m -> m.Text1), SetText1)
"Text2" |> Binding.twoWay ((fun m -> m.Text2), SetText2)
"Submit" |> Binding.cmd Submit
]


module App =

type Dialog =
| Form1 of Form1.Model
| Form2 of Form2.Model
type Dialog =
| Form1 of Form1.Model
| Form2 of Form2.Model

type Model = { Dialog: Dialog option }

let init () = { Dialog = None }

type Msg =
| ShowForm1
| ShowForm2
| Form1Msg of Form1.Msg
| Form2Msg of Form2.Msg

let update msg m =
match msg with
| ShowForm1 -> { m with Dialog = Some <| Form1 Form1.init }
| ShowForm2 -> { m with Dialog = Some <| Form2 Form2.init }
| Form1Msg Form1.Submit -> { m with Dialog = None }
| Form1Msg msg' ->
match m.Dialog with
| Some (Form1 m') -> { m with Dialog = Form1.update msg' m' |> Form1 |> Some }
| _ -> m
| Form2Msg Form2.Submit -> { m with Dialog = None }
| Form2Msg msg' ->
match m.Dialog with
| Some (Form2 m') -> { m with Dialog = Form2.update msg' m' |> Form2 |> Some }
| _ -> m


[<AllowNullLiteral>]
type App_ViewModel (args) =
inherit ViewModelBase<App.Model, App.Msg>(args)

// bindings
let form1Visible_Binding =
Binding.OneWayT.id
>> Binding.mapModel (fun (m: App.Model) ->
match m.Dialog with
| Some (App.Dialog.Form1 _) -> true
| _ -> false)


let form2Visible_Binding =
Binding.OneWayT.id
>> Binding.mapModel (fun (m: App.Model) ->
match m.Dialog with
| Some (App.Dialog.Form2 _) -> true
| _ -> false)


let form1_Binding =
Binding.SubModelT.opt Form1_ViewModel
>> Binding.mapModel (fun (m: App.Model) ->
match m.Dialog with
| Some (App.Dialog.Form1 m') -> ValueSome m'
| _ -> ValueNone)
>> Binding.mapMsg (fun msg -> App.Form1Msg msg)


type Model =
{ Dialog: Dialog option }
let form2_Binding =
Binding.SubModelT.opt Form2_ViewModel
>> Binding.mapModel (fun (m: App.Model) ->
match m.Dialog with
| Some (App.Dialog.Form2 m') -> ValueSome m'
| _ -> ValueNone)
>> Binding.mapMsg (fun msg -> App.Form2Msg msg)

let init () =
{ Dialog = None }

type Msg =
| ShowForm1
| ShowForm2
| Form1Msg of Form1.Msg
| Form2Msg of Form2.Msg
new() = App_ViewModel(App.init () |> ViewModelArgs.simple)

let update msg m =
match msg with
| ShowForm1 -> { m with Dialog = Some <| Form1 Form1.init }
| ShowForm2 -> { m with Dialog = Some <| Form2 Form2.init }
| Form1Msg Form1.Submit -> { m with Dialog = None }
| Form1Msg msg' ->
match m.Dialog with
| Some (Form1 m') -> { m with Dialog = Form1.update msg' m' |> Form1 |> Some }
| _ -> m
| Form2Msg Form2.Submit -> { m with Dialog = None }
| Form2Msg msg' ->
match m.Dialog with
| Some (Form2 m') -> { m with Dialog = Form2.update msg' m' |> Form2 |> Some }
| _ -> m

let bindings () : Binding<Model, Msg> list = [
"ShowForm1" |> Binding.cmd ShowForm1
// members
member _.ShowForm1 = base.Get () (Binding.CmdT.setAlways App.ShowForm1)

"ShowForm2" |> Binding.cmd ShowForm2
member _.ShowForm2 = base.Get () (Binding.CmdT.setAlways App.ShowForm2)

"DialogVisible" |> Binding.oneWay (fun m -> m.Dialog.IsSome)
member _.DialogVisible =
base.Get
()
(Binding.OneWayT.id
>> Binding.mapModel (fun m -> m.Dialog.IsSome))

"Form1Visible" |> Binding.oneWay
(fun m -> match m.Dialog with Some (Form1 _) -> true | _ -> false)

"Form2Visible" |> Binding.oneWay
(fun m -> match m.Dialog with Some (Form2 _) -> true | _ -> false)
member _.Form1Visible = base.Get () (form1Visible_Binding)

"Form1"
|> Binding.SubModel.opt Form1.bindings
|> Binding.mapModel (fun m -> match m.Dialog with Some (Form1 m') -> Some m' | _ -> None)
|> Binding.mapMsg Form1Msg
member _.Form2Visible = base.Get () (form2Visible_Binding)

"Form2"
|> Binding.SubModel.opt Form2.bindings
|> Binding.mapModel (fun m -> match m.Dialog with Some (Form2 m') -> Some m' | _ -> None)
|> Binding.mapMsg Form2Msg
]
member _.Form1 = base.Get () (form1_Binding)

member _.Form2 = base.Get () (form2_Binding)

let form1DesignVm = ViewModel.designInstance Form1.init (Form1.bindings ())
let form2DesignVm = ViewModel.designInstance Form2.init (Form2.bindings ())
let mainDesignVm = ViewModel.designInstance (App.init ()) (App.bindings ())


let main window =
module Program =
let main window =

let logger =
LoggerConfiguration()
.MinimumLevel.Override("Elmish.WPF.Update", Events.LogEventLevel.Verbose)
.MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose)
.MinimumLevel.Override("Elmish.WPF.Performance", Events.LogEventLevel.Verbose)
.WriteTo.Console()
.CreateLogger()
let logger =
LoggerConfiguration()
.MinimumLevel.Override("Elmish.WPF.Update", Events.LogEventLevel.Verbose)
.MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose)
.MinimumLevel.Override("Elmish.WPF.Performance", Events.LogEventLevel.Verbose)
.WriteTo.Console()
.CreateLogger()

WpfProgram.mkSimple App.init App.update App.bindings
|> WpfProgram.withLogger (new SerilogLoggerFactory(logger))
|> WpfProgram.startElmishLoop window
WpfProgram.mkSimpleT App.init App.update App_ViewModel
|> WpfProgram.withLogger (new SerilogLoggerFactory(logger))
|> WpfProgram.startElmishLoop window
15 changes: 7 additions & 8 deletions src/Samples/SubModelOpt/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
using System;
using System.Windows;

namespace Elmish.WPF.Samples.SubModelOpt
namespace Elmish.WPF.Samples.SubModelOpt;

public partial class App
{
public partial class App : Application
{
public App()
{
this.Activated += StartElmish;
this.Activated += StartElmish;
}

private void StartElmish(object sender, EventArgs e)
{
this.Activated -= StartElmish;
Program.main(MainWindow);
this.Activated -= StartElmish;
Program.Program.main(MainWindow);
}

}
}
}
43 changes: 29 additions & 14 deletions src/Samples/SubModelOpt/Form1.xaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
<UserControl x:Class="Elmish.WPF.Samples.SubModelOpt.Form1"
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.SubModelOpt;assembly=SubModelOpt.Core"
Padding="10"
mc:Ignorable="d"
d:DataContext="{x:Static vm:Program.form1DesignVm}">
<StackPanel Width="300">
<TextBlock Text="Form 1" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,0,0,5" />
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" TextWrapping="Wrap" AcceptsReturn="True" Height="80" Margin="0,5,0,5" />
<Button Command="{Binding Submit}" Content="Submit" />
</StackPanel>
<UserControl
x:Class="Elmish.WPF.Samples.SubModelOpt.Form1"
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:vm="clr-namespace:Program;assembly=SubModelOpt.Core"
Padding="10"
d:DataContext="{d:DesignInstance Type=vm:Form1_ViewModel,
IsDesignTimeCreatable=True}"
mc:Ignorable="d">
<StackPanel
Width="300">
<TextBlock
Margin="0,0,0,5"
HorizontalAlignment="Center"
FontSize="18"
FontWeight="Bold"
Text="Form 1" />
<TextBox
Height="80"
Margin="0,5,0,5"
AcceptsReturn="True"
Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
<Button
Command="{Binding Submit}"
Content="Submit" />
</StackPanel>
</UserControl>
Loading
Loading