Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / F#

Mixing MVVM with RX - Part 3

5.00/5 (2 votes)
25 Oct 2015CPOL1 min read 5.6K  
CodeProject Lately I have been playing around with F#, and I must admit I like the language a lot ! I think it is very expressive and very intuitive to use.I personally think that the best way to learn a new language is to find a project that you are familiar with (you have implemented in the l

Lately I have been playing around with F#, and I must admit I like the language a lot ! I think it is very expressive and very intuitive to use.

I personally think that the best way to learn a new language is to find a project that you are familiar with (you have implemented in the language you are familiar with) and then try to convert it to the new language.

So I decided to try and convert the RX MVVM framework that I showed in the first blog on this series and convert it to F#.

The first interface IPropertySubject is declared as :

F#
type IPropertySubject<'t> =
    inherit IObservable<'t>
    abstract member Value : 't with get, set

Then the implementation looks like:

F#
type PropertySubject<'t>() =
    let _subject : Subject<'t> = new Subject<'t>()
    let mutable _value : 't = Unchecked.defaultof<'t>
    let setValue v =
        _value <- v
        _subject.OnNext(v)
    member x.SetValues(obs : IObservable<'t>) =
        obs.Subscribe(fun v -> setValue v)
    member x.SetValue(value : 't) = setValue value

    interface IPropertySubject<'t> with
        member x.Value with get() = _value and set v = setValue v
        member x.Subscribe observer =
            _subject.Subscribe observer

The next interface is ICommandObserver. the interface is declared as follows:

F#
type ICommandObserver<'t> =
    inherit ICommand
    abstract member Execute : IObservable<'t>  with get
    abstract member CanExecute : IObserver<bool> with get

And the implementation :

F#
type CommandObserver<'t>(value) as self =
    let event = Event<_, _>()
    let _executeSubject = new Subject<'t>()
    let _canExecuteSubject = new Subject<bool>()
    let mutable _canExecute = value
    let disp = _canExecuteSubject.DistinctUntilChanged().Subscribe(fun v -> _canExecute <- v
                                                                            event.Trigger(self, EventArgs.Empty))
    new() = new CommandObserver<'t>(true)
    member x.SubscribeOnValues (values : IObservable<bool>)  =
        values.Subscribe(_canExecuteSubject)
    interface ICommandObserver<'t> with  
        member x.Execute with get() = _executeSubject.AsObservable()
        member x.CanExecute with get() = _canExecuteSubject.AsObserver()
                                                                  
    interface ICommand with  
        member x.add_CanExecuteChanged(e) = event.Publish.AddHandler(e)                                                                       
        member x.remove_CanExecuteChanged(e) = event.Publish.RemoveHandler(e)
        member x.Execute parameter =
            match parameter with            | :? 't -> _executeSubject.OnNext(parameter :?> 't)
            | _ -> _executeSubject.OnNext(Unchecked.defaultof<'t>)    
        member x.CanExecute parameter =
            _canExecute

The next step is to implement ViewModelBase. The implementation in F# looks like:

F#
type ViewModelBase() =
    let event = Event<_, _>()
    member x.OnPropertyChanged(propName : string) =
        event.Trigger(x, new PropertyChangedEventArgs(propName))
    interface INotifyPropertyChanged with       
        member x.add_PropertyChanged(e) = event.Publish.AddHandler(e)
        member x.remove_PropertyChanged(e) = event.Publish.RemoveHandler(e)

One we have ViewModelBase, then it is time to declare IPropertyProvider interface. The declaration for the interface looks like:

F#
type IPropertyProvider<'viewmodel> =
    inherit IDisposable
    abstract member CreateProperty<'ttype> : Expression<System.Func<'viewmodel,'ttype>> -> IPropertySubject<'ttype> 
    abstract member CreateProperty<'ttype> : Expression<System.Func<'viewmodel,'ttype>> * 'ttype -> IPropertySubject<'ttype> 
    abstract member CreateProperty<'ttype> : Expression<System.Func<'viewmodel,'ttype>> * IObservable<'ttype> -> IPropertySubject<'ttype> 
    abstract member CreateCommand<'ttype> : Expression<System.Func<'viewmodel, ICommand>> -> ICommandObserver<'ttype>
    abstract member CreateCommand<'ttype> : Expression<System.Func<'viewmodel, ICommand>> * bool -> ICommandObserver<'ttype>
    abstract member CreateCommand<'ttype> : Expression<System.Func<'viewmodel, ICommand>> * IObservable<bool> -> ICommandObserver<'ttype>

And the implementation is :

F#
type PropertyProvider<'viewmodel>(viewModelBase : ViewModelBase, schedulers : ISchedulers) =
    let _viewModelBase = viewModelBase
    let _disposables = new CompositeDisposable()
 
    let getProperty (expr : Expression<System.Func<'viewmodel,'ttype>>) =
        let propName = (expr.Body :?> MemberExpression).Member.Name
        let propSubject = new PropertySubject<'t>()
        propSubject.SubscribeOn(schedulers.Dispatcher).Subscribe(fun _ -> _viewModelBase.OnPropertyChanged(propName))
        |> _disposables.Add 
        propSubject
 
    interface IPropertyProvider<'viewmodel> with
        member x.CreateProperty<'ttype> expr =
            let propSubject = getProperty expr
            propSubject :> IPropertySubject<'ttype>
 
        member x.CreateProperty<'ttype> (expr : Expression<System.Func<'viewmodel,'ttype>>, value : IObservable<'ttype>) =
            let propSubject = getProperty expr
            propSubject.SetValues(value) |> _disposables.Add
            propSubject :> IPropertySubject<'ttype>
 
        member x.CreateProperty<'ttype> (expr : Expression<System.Func<'viewmodel,'ttype>>, value : 'ttype) =
            let propSubject = getProperty expr
            propSubject.SetValue(value)
            propSubject :> IPropertySubject<'ttype>
                        
        member x.CreateCommand<'ttype> expr =
            new CommandObserver<'ttype>(true) :> ICommandObserver<'ttype>
 
        member x.CreateCommand<'ttype>(expr : Expression<System.Func<'viewmodel, ICommand>>, value : bool) =
            new CommandObserver<'ttype>(value) :> ICommandObserver<'ttype>
 
        member x.CreateCommand<'ttype>(expr : Expression<System.Func<'viewmodel, ICommand>>, values : IObservable<bool>) =
            let cmdObserver = new CommandObserver<'ttype>() 
            cmdObserver.SubscribeOnValues(values) |> _disposables.Add
            cmdObserver :> ICommandObserver<'ttype>
                
    interface IDisposable with
        member x.Dispose() =
            _disposables.Dispose()

The next step is to declare a factory that will create property provider. The interface for the factory looks like :

F#
type IPropertyProviderFactory = 
    abstract member Create<'t> : ViewModelBase -> IPropertyProvider<'t>  

The implementation of the interface looks like :

F#
type PropertyProviderFactory(schedulers : ISchedulers) =
    interface IPropertyProviderFactory with
        member x.Create<'t> (vm : ViewModelBase) =
            new PropertyProvider<'t>(vm, schedulers) :> IPropertyProvider<'t>

Next we need to implement message bus. The interface for the message bus is as follows :

F#
type IMessageBus = 
    abstract member Subscribe<'t> : System.Action<'t> -> IDisposable
    abstract member Publish<'t> : 't -> unit

And the implementation is :

F#
type MessageBus() =
    let _messageBus = new Subject<Object>()
    interface IMessageBus with
        member x.Subscribe<'t> onNext =
            _messageBus.OfType<'t>().Subscribe(onNext) 
        member x.Publish<'t>(value : 't)  =
            _messageBus.OnNext(value :> Object)

And lastly we will declare and implement schedulers. The interface for the schedulers looks like :

F#
type ISchedulers =
    abstract member Dispatcher : IScheduler with get
    abstract member NewThread : IScheduler with get
    abstract member NewTask : IScheduler with get
    abstract member ThreadPool : IScheduler with get
    abstract member Timer : IScheduler with get

And the implementation is as follows:

F#
type Schedulers(guiSynchronizationContext : IGuiSynchronizationContext) =
    let _dispatcher = new SynchronizationContextScheduler(guiSynchronizationContext.SynchronizationContext)
    interface ISchedulers with
        member x.Dispatcher with get() = _dispatcher :> IScheduler
        member x.NewThread with get() = Scheduler.NewThread :> IScheduler
        member x.NewTask with get() = Scheduler.TaskPool :> IScheduler
        member x.ThreadPool with get() = Scheduler.ThreadPool :> IScheduler
        member x.Timer with get() = Scheduler.Immediate :> IScheduler

As you can see from the code above, F# code is a lot more compact and has a lot less boilerplate and ceremony. 

I hope you find it interesting and helpful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)