Click here to Skip to main content
15,887,083 members
Articles / Programming Languages / F#

Mixing MVVM with RX - Part 3

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
25 Oct 2015CPOL1 min read 5.3K   1   3
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)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionDownload? Pin
Shabbazz22-Dec-16 18:51
professionalShabbazz22-Dec-16 18:51 
AnswerRe: Download? Pin
Fitim Skenderi28-Dec-16 14:42
professionalFitim Skenderi28-Dec-16 14:42 
GeneralRe: Download? Pin
Shabbazz12-Jan-17 3:13
professionalShabbazz12-Jan-17 3:13 
Hi Fitim,

thanks a lot!

Best regards,
Volker

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.