Giter Site home page Giter Site logo

exploreelmishwpf's People

Contributors

benttranberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

telgwin

exploreelmishwpf's Issues

Automatic saving of updated textbox values

I am using Form2 of ExploreElmishWpf

  • to demonstrate a problem with automatic saving of textbox updated values that arisen due to my faulty preconceptions, and
  • to present a solution.

The Form2 tab consists of two textboxes and a submit button. The submit button will not be used. The updated textbox values are intended to be automatically saved into an xml file. For the sake of simplicity, deserialization and further usage of saved values are omitted.

Notice where the myUpdate function in the update function is placed (Form2.fs) and notice the binding in the Text property (Form2.xaml):

Form2.fs

namespace ExploreElmishWpf.Models

open System
open System.IO;
open Newtonsoft.Json //Install-Package Newtonsoft.Json -Version 13.0.1 

open System.Runtime.Serialization

type TestRecord = 
    {      
        input1: string
        input2: string
    }

module Serialisation = 
         //simplified serialisation without FileInfo checks, try-with blocks and without Option.ofObj
         let serialize record =             
             let filepath = Path.GetFullPath("json.xml") 
             let xmlSerializer = new DataContractSerializer(typedefof<string>)  
             use stream = File.Create(filepath)   
             xmlSerializer.WriteObject(stream, JsonConvert.SerializeObject(record))  

module Form2 =
    open System
    open Elmish
    open Elmish.WPF
    open Serialisation

    type Model =
        {
            Input1: string
            Input2: string
        }

    type Msg =
        | Text1Input of string
        | Text2Input of string
        | Submit // not used

    let init =
        {
            Input1 = "Value in txtBox1"
            Input2 = "Value in txtBox2"
        }

    let myUpdate m = 
        let myCopyOfTestRecord =  //this is what should be saved into json.xml
            {
                input1 = m.Input1       
                input2 = m.Input2       
            }                
        serialize myCopyOfTestRecord
        m 
    
    let update msg m =
        match msg with
        | Text1Input s -> { myUpdate m with Input1 = s } 
        | Text2Input s -> { myUpdate m with Input2 = s } 
        | Submit -> m  // not used      

    let bindings () : Binding<Model, Msg> list =
        [
            "Input1" |> Binding.twoWay ((fun m -> m.Input1), (fun newVal -> newVal |> Text1Input))  
            "Input2" |> Binding.twoWay ((fun m -> m.Input2), (fun newVal -> newVal |> Text2Input))            
            "Submit" |> Binding.cmd Submit // not used
        ]

Form2.xaml

<UserControl x:Class="ExploreElmishWpf.Form2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"             
             xmlns:local="clr-namespace:ExploreElmishWpf"
             mc:Ignorable="d" 
             Padding="10">
   
    <StackPanel Width="300">
        <TextBlock Text="Form 2" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,0,0,5" />
        <TextBox Text="{Binding Input1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="0,5,0,5">          
        </TextBox>
        <TextBox Text="{Binding Input2, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="0,5,0,5">          
        </TextBox>
        <Button Command="{Binding Submit}" Content="Submit" />
    </StackPanel>
</UserControl>

Run the app and type "Hello" and leave "Value in txtBox2" and look at the content of json.xaml in the Debug (or Release respectively) folder. "Hell" and "Value in txtBox2" are saved. Type "Hello" into both textboxes and look at json.xaml - "Hello" and "Hell" are saved.
The last character is not saved. I think it is because the myUpdate function is fired BEFORE the UpdateSourceTrigger property is triggered.

My solution consists of creating a separate Update message initiated by a TextChanged event. Like in the following code.

Form2.fs

namespace ExploreElmishWpf.Models

open System
open System.IO;
open Newtonsoft.Json //Install-Package Newtonsoft.Json -Version 13.0.1 

open System.Runtime.Serialization

type TestRecord = 
    {      
        input1: string
        input2: string
    }

module Serialisation = 
         //simplified serialisation without FiloInfo checks, try-with blocks and without Option.ofObj
         let serialize record =             
             let filepath = Path.GetFullPath("json.xml") 
             let xmlSerializer = new DataContractSerializer(typedefof<string>)  
             use stream = File.Create(filepath)   
             xmlSerializer.WriteObject(stream, JsonConvert.SerializeObject(record))  

module Form2 =

    open System
    open Elmish
    open Elmish.WPF
    open Serialisation

    type Model =
        {
            Input1: string
            Input2: string
        }

    type Msg =
        | Text1Input of string
        | Text2Input of string
        | Submit // not used
        | Update

    let init =
        {
            Input1 = "Value in txtBox1"
            Input2 = "Value in txtBox2"
        }

    let myUpdate m = 
        let myCopyOfTestRecord =  //this is what should be saved into json.xml
            {
                input1 = m.Input1       
                input2 = m.Input2       
            }                
        serialize myCopyOfTestRecord
        m 
    
    let update msg m =
        match msg with
        | Text1Input s -> { m with Input1 = s } //compare with { myUpdate m with Input1 = s }
        | Text2Input s -> { m with Input2 = s } //compare with { myUpdate m with Input1 = s }
        | Submit -> m  // not used
        | Update -> myUpdate m

    let bindings () : Binding<Model, Msg> list =
        [
            "Input1" |> Binding.twoWay ((fun m -> m.Input1), (fun newVal -> newVal |> Text1Input))  
            "Input2" |> Binding.twoWay ((fun m -> m.Input2), (fun newVal -> newVal |> Text2Input))
            "Update" |> Binding.cmd Update 
            "Submit" |> Binding.cmd Submit // not used
        ]

Form2.xaml

<UserControl x:Class="ExploreElmishWpf.Form2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:local="clr-namespace:ExploreElmishWpf"
             mc:Ignorable="d" 
             Padding="10">
    <!-- 
    Install-Package Microsoft.Xaml.Behaviors.Wpf -Version 1.1.39
    -->
    <StackPanel Width="300">
        <TextBlock Text="Form 2" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,0,0,5" />
        <TextBox Text="{Binding Input1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="0,5,0,5">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="TextChanged">
                    <i:InvokeCommandAction PassEventArgsToCommand="False" Command="{Binding Update}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>
        <TextBox Text="{Binding Input2, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="0,5,0,5">
            <i:Interaction.Triggers>               
                <i:EventTrigger EventName="TextChanged">
                    <i:InvokeCommandAction PassEventArgsToCommand="False" Command="{Binding Update}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>
        <Button Command="{Binding Submit}" Content="Submit" />
    </StackPanel>
</UserControl>

If you know of a better solution, thanx for sharing it here :-) .

Example usage of Elmish with WPF Tab Control

I have a WPF Tab Control (in C#) where each tab uses a different UserControl with a different ViewModel as datacontext. In the C# application, only the Tab being viewed has the active window. As I'm a newbie to Elmish (and F#), an example of how to switch between tabs with Elmish would be most appreciated.

Thanks. AW

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.