reactiveui / ReactiveUI

An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms that is inspired by functional reactive programming. ReactiveUI allows you to abstract mutable state away from your user interfaces, express the idea around a feature in one readable place and improve the testability of your application.
https://www.reactiveui.net
MIT License
8.09k stars 1.12k forks source link

Add class ObservableBinding #85

Closed bradphelan closed 12 years ago

bradphelan commented 12 years ago

I have created a helper class called ObservableBinding which is like a mini view model with only a single property Value. I've added an extension method for binding ObservableBindings to controls and the resulting code is much simpler for quickly binding plain old objects to UI elements, at least for output only cases.

For example

    var model = GetWindSpeedModel()

    var vm = model.ObservablePropertyFor(x => x.WindSpeed).
            Select(x => x.ToString("00.00)).
            ToObservableBinding();

    WindSpeedLabel.AddBinding( c => c.Text, vm); 

Note that I don't have to create a ViewModel class to hold my binding. I can transform and bind directly from my domain object.

The class is ( in VB.NET sorry ) but quite simple

    Imports System.ComponentModel
    Imports System.Runtime.CompilerServices
    Imports System.Reactive.Linq
    Imports ReactiveUI
    Imports System.Linq.Expressions

    ''' <summary>
    ''' Converts an observable into an object that supports INPC
    ''' and thus can be bound to a control
    ''' </summary>
    ''' <typeparam name="T"></typeparam>
    ''' <remarks></remarks>
    Public Class ObservableBinding(Of T)

        Inherits ReactiveUI.ReactiveObject

        Private _Value As ObservableAsPropertyHelper(Of T)
        Public ReadOnly Property Value As T
            Get
                Return _Value.Value
            End Get
        End Property

        Public Sub New(observable As IObservable(Of T), Optional defaultValue As T = Nothing)
            _Value = observable.ToProperty(Me, Function(x) x.Value)
        End Sub

    End Class

    Module ObservableBinding
        <Extension>
        Public Function ToObservableBinding(Of T)(this As IObservable(Of T), Optional defaultValue As T = Nothing) As ObservableBinding(Of T)
            Return New ObservableBinding(Of T)(this, defaultValue)
        End Function

        ''' <summary>
        ''' Adds an ObservableBinding as a binding to the control. ObservableBinding
        ''' objects have only one property called Value and this will be bound
        ''' to the control property
        ''' </summary>
        ''' <typeparam name="TControl"></typeparam>
        ''' <typeparam name="TControlProperty"></typeparam>
        ''' <param name="control"></param>
        ''' <param name="controlPropertyName"></param>
        ''' <param name="source"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()>
        Public Function AddBinding(Of TControl As Control, TControlProperty)(
                control As TControl,
                controlPropertyName As Expression(Of Func(Of TControl, TControlProperty)),
                source As ObservableBinding(Of TControlProperty)) As Binding

            Return control.AddBinding(
                controlPropertyName,
                source,
                Function(x) x.Value)
        End Function

        <Extension()>
        Public Function AddBinding(Of TControl As Control, TControlProperty)(
            control As TControl,
            propertyName As Expression(Of Func(Of TControl, TControlProperty)),
            observable As IObservable(Of TControlProperty),
            Optional defaultValue As TControlProperty = Nothing) As ObservableBinding(Of TControlProperty)

            Dim inpc = observable.ToObservableBinding(defaultValue)

            control.AddBinding(propertyName, inpc, Function(_c) _c.Value)

            Return inpc

        End Function

    End Module
bradphelan commented 12 years ago

I just discovered BindTo :)

anaisbetts commented 12 years ago

Hm, I would do this as:


var model = GetWindSpeedModel();

model.WhenAny(x => x.WindSpeed, x => x.Value.ToString("00.00"))
    .BindTo(theView, x => x.Text);
bradphelan commented 12 years ago

But it doesn't work with winform, only wpf. the dispatcher logic is all wrong. I'm working on a winforms addition to reactive ui at the moment. It avoids properties and just uses observables.