MVVM – f#async / await in view model
My ViewModel in F #
I'm trying to use f# instead of c# to implement my ViewModel I'm following this article (by the way, do you have any new or better suggestions?)
So, suppose I have my view model library implementation (MVVM. ViewModel, which is in C #, but I can refer to it from F #) and a simple status attribute
namespace Funcviewmodel
open MVVM.viewmodel
open System
    type MyFuncviewmodel() = 
        inherit viewmodelBase()
        let mutable status=""
        member this.RunSetStatus() =
            status <- "Reset @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
            base.OnPropertyChanged("Status")
        member this.SetStatus = new DelegateCommand(fun _ -> this.RunSetStatus() )
    member this.Status 
        with get() =
            status
        and set(value) =
             status <- value
             base.OnPropertyChanged(fun () -> this.Status)
Everything worked as expected and has been good so far (but if you find any conceptual errors, or if you find a more common version of the above code, please let me know)
Introduce async / await mode
This is where I went wrong: I know how to do this in C #, but I'm not good at f #
I've tried the following
member this.RunSetStatus() =
    status <- "Start resetting @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
    base.OnPropertyChanged("Status")
    let task = async {
        do! Async.Sleep (30 * 1000) 
    }
    Async.StartImmediate(task)
    status <- "Reset done @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
    base.OnPropertyChanged("Status")
The problem is - when I run a full WPF application - I don't see the expected delay: the final state is output directly to the output
If I put the above async Change startimmediate to async Runsynchronously (task), of course I see the ongoing delay, but the application is frozen, so this is not what I want
If I rearrange them as
member this.RunSetStatus() =
    status <- "Start resetting @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
    base.OnPropertyChanged("Status")
    let task = async {
        do! Async.Sleep (30 * 1000) 
        status <- "Reset done @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
        base.OnPropertyChanged("Status")
    }
    Async.StartImmediate(task)
I received an error
Editing (Continued)
Finally, I tried this
member this.RunSetStatus() =
    status <- "Start resetting @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
    base.OnPropertyChanged("Status")
    let task = async {
        do! Async.Sleep (30 * 1000) 
    }
    Async.StartWithContinuations(task,(fun _ -> this.Status <- "Reset done @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"),(fun _ -> this.Status <- "Operation Failed."),(fun _ -> this.Status <- "Operation canceled."))
However, argumentexception occurs when the application crashes
stack trace
Edit 2 – problems found
I have to use the following - more simply - the overload of onpropertychanged (they are implemented according to this source code and work in c#)
member this.Status 
        with get() =
            status
        and set(value) =
             status <- value
             base.OnPropertyChanged("Status")
Solution
The reason for the exception is that f#'s function cannot be expressed as memberexpression:
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        MemberExpression body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }
In the debugger, you will see the exception actually obtained - "the body must be a member expression"
Your first code:
member this.RunSetStatus() =
    status <- "Reset @" + DateTime.Now.ToString "yy.MM.dd hh:mm:ss"
    base.OnPropertyChanged("Status")
Because you do not use the property setter state, it works normally
So you need to use different overloads
