views:

156

answers:

3

I was just reading Rx HOL NET. Upon finding (example uses Windows Forms):

var moves = Observable.FromEvent<MouseEventArgs>(frm, "MouseMove");

I wonder how can I instantiate and pass the reference to moves to ViewModel in some WPF MVVM setup? In my understanding it does make sense to try and filter this stream of data inside ViewModel.

Or, how to do something similar for keyboard input into TextBox? In this scenario you wouldn't, for example, attach some text masking behavior to a control in XAML but would, instead, let Observer in VM filter and validate keyboard input.

Am I completely off the track?

+1  A: 

This might help: Reactive Extensions (Rx) + MVVM = ?

Richard Hein
I found that useful indeed but am still struggling to see how exactly to implement HOL sample with Web service dictionary in MVVM way.
Tony
+1  A: 

The easiest way of doing the keyboard sample would be to two-way bind the text to a property of the ViewModel. The Text setter could then write to a private Subject that the rest of your code uses as a basis of IObservable<string>. From there, you can complete the HOL sample.

Mouse movements are generally considered too "view" to put in the ViewModel, but if the logic that came off it was complex enough, you could have it execute an ICommand or perhaps put the logic into a behavior. If it were an ICommand, you could have the command have a WhenExecuted IObservable property that you could pick up in your ViewModel.`

Richard Szalay
I would really like to see more complete examples in blogs around.
Tony
+1  A: 

Here is an example of how you could implement the web service dictionary in a MVVM fashion. It has three parts:

  1. The ObservablePropertyBacking class, a backing for properties (of T) that also implements IObservable
  2. The MyViewModel class. It contains a property CurrentText which uses an ObservablePropertyBacking as backing storage. It also observes the value of this property and uses it to call the dictionary web service.
  3. The MainView.xaml which contains a TextBox. Its Text property is two-way bound to the CurrentText property on the view model.

MyViewModel.cs:

class MyViewModel: INotifyPropertyChanged
{
    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string p)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(p));
    }

    #endregion

    public MyViewModel()
    {
        SetupProperties();
    }

    #region CurrentText

    /*  We use a special class for backing of the CurrentText property. This object
     *  holds the value of the property and also dispatches each change in an observable 
     *  sequence, i.e. it implements IObservable<T>.
     */
    private ObservablePropertyBacking<string> _textInput;
    public string CurrentText
    {
        get { return _textInput.Value; }
        set
        {
            if (value == _textInput.Value) { return; }
            _textInput.Value = value;
            RaisePropertyChanged("CurrentText");
        }
    }

    #endregion

    /*  Create property backing storage and subscribe UpdateDictionary to the observable 
        *  sequence. Since UpdateDictionary calls a web service, we throttle the sequence.
        */
    private void SetupProperties()
    {
        _textInput = new ObservablePropertyBacking<string>();
        _textInput.Throttle(TimeSpan.FromSeconds(1)).Subscribe(UpdateDictionary);
    }

    private void UpdateDictionary(string text)
    {
        Debug.WriteLine(text);
    }
}

ObservablePropertyBacking.cs:

public class ObservablePropertyBacking<T> : IObservable<T>
{
    private Subject<T> _innerObservable = new Subject<T>();

    private T _value;
    public T Value
    {
        get { return _value; }
        set
        {
            _value = value;
            _innerObservable.OnNext(value);
        }
    }

    public IDisposable Subscribe(IObserver<T> observer)
    {
        return _innerObservable
            .DistinctUntilChanged()
            .AsObservable()
            .Subscribe(observer);
    }
}

MainPage.xaml:

  <Window 
    x:Class="RxMvvm_3435956.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
      <TextBox
        Text="{Binding CurrentText, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
  </Window>
Markus Johnsson