11

I am looking for a sample that demonstrates in the lightest way possible the following:

A Model that invokes a SOAP based web service; regularly polling to get the latest value (assume the SOAP service returns a boolean). The model should also support invoking a SOAP method that changes the boolean on the server.

A ViewModel that enables the underlying boolean to be bound to controls in the View (e.g. to a checkbox).

A View with the above checkbox control bound to the underlying boolean. Depending on the poll interval the checkbox will update as the server's state changes. If the checkbox is clicked the event will be dispatched to the model causing the server to be updated.

Optimally this sample will work on Windows Phone 7, but in a pinch I'd be happy with something that supported SL3 (no use of SL4 command routing allowed).

I am struggling with trying to understand how to make MVVM-Light work for me and I suspect that an expert could code a sample up like this very quickly... I also suspect this is a fairly common pattern for a lot of apps.

tig
  • 3,424
  • 3
  • 32
  • 65
  • Polling a server from a mobile device is at best a code smell but typically an anti-pattern as it has resource usage implications. You should look at having the server process send a notification when the value returned by the service changes. You're also likely to get more help if you can demonstrate what you've tried and the problems you've encountered. Asking for someone to write a working example is rarely a successful strategy to get assistance. – Matt Lacey Sep 07 '10 at 09:21
  • Fair comment about writing an app with specific requirements for someone, but if a sample is available that demonstrates at least one of the major fundamentals that can be linked then that's a start to build on. – Mick N Sep 07 '10 at 10:13
  • Check this blog post out by Joost van Schaik that was recently linked (by kP from memory?) over at wp7 forums. http://dotnetbyexample.blogspot.com/2010/07/using-mvvm-light-to-drive-windows-phone.html I doubt you'll find a "sample" that also happens to implement your "requirements", but at least with a sample that does what your question title describes you can learn and then apply your more detailed requirements to it. – Mick N Sep 07 '10 at 10:00
  • Joost's example was super helpful to me as well. It was not as simple as I had hoped for, but it did expose a couple of the key patterns. Thanks. – tig Sep 08 '10 at 20:44

1 Answers1

8

Mick N's pointer helped, but what really got me over the hump was this post by Jeremy Likness: http://csharperimage.jeremylikness.com/2010/04/model-view-viewmodel-mvvm-explained.html

Here's the sample for the benefit of others (assuming I'm not doing anything really stupid):

First, I started using the Mvvm-Light Windows Phone 7 project.

I added a checkbox to my MainPage.xaml:

    <CheckBox Content="Switch 1" 
              IsChecked="{Binding Switch1.PowerState, Mode=TwoWay}"
              Height="72" HorizontalAlignment="Left" Margin="24,233,0,0" 
              Name="checkBox1" VerticalAlignment="Top" Width="428" />

Notice the IsChecked is bound to Switch1.PowerState using the TwoWay mode so that the property flows both ways.

A key learning for me is how to enable communication from my timer callback (TimerCB) which will be running on a new thread to the Silverlight UI thread. I used the Mvvm-Light DispatcherHelper.CheckBeginInvokeOnUI helper which waits on the UI thread.

I then had to decide whether to implement INotifyPropertyChanged myself in my model, or use Mvvm-Light's ViewModelBase implementation. I actually tried it both ways and had it working but decided I liked using ViewModelBase better because it supports "broadcast" and I think in my actual project that will be handy because I will have multiple ViewModels. It seems a bit uncouth to be basing a "Model" on ViewModelBase class, but I don't think there's any harm in doing so. (???).

My model .cs is below.

public class OnOffSwitchClass : ViewModelBase // ignore that it's derived from ViewModelBase!
{
    private const Int32 TIMER_INTERVAL = 5000;  // 5 seconds
    private Timer _timer;

    // Upon creation create a timer that changes the value every 5 seconds
    public OnOffSwitchClass()
    {
        _timer = new System.Threading.Timer(TimerCB, this, TIMER_INTERVAL, TIMER_INTERVAL);
    }

    private static void TimerCB(object state)
    {
        // Alternate between on and off
        ((OnOffSwitchClass)state).PowerState = !((OnOffSwitchClass)state).PowerState;
    }

    public const string PowerStatePropertyName = "PowerState";

    private bool _myProperty = false;

    public bool PowerState
    {
        get
        {
            return _myProperty;
        }

        set
        {
            if (_myProperty == value)
            {
                return;
            }

            var oldValue = _myProperty;
            _myProperty = value;

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            GalaSoft.MvvmLight.Threading.DispatcherHelper.CheckBeginInvokeOnUI(() =>
                RaisePropertyChanged(PowerStatePropertyName, oldValue, value, true));
        }
    }
}

The MainViewModel.cs was modified to include the following

private OnOffSwitchClass _Switch1 = new OnOffSwitchClass();

public OnOffSwitchClass Switch1 
{
    get
    {
        return _Switch1;
    }
}

And I added a call to DispatcherHelper.Initialize(); in my App() constructor.

Does this look right?

tig
  • 3,424
  • 3
  • 32
  • 65
  • 1
    As far as the Model question, in WP7 I use a model class for reading/writing to Transient memory and Isolated storage. ViewModels are for presenting data to be bound to by the Views/Pages. If you're using your Model like a view model, then maybe it should be a view model. – Matt Casto Sep 08 '10 at 16:14
  • I prefer calling DispatcherHelper.Initialize() in both App.xaml.cs' Appliance_Launching and Appliance_Activated methods. – Matt Casto Sep 08 '10 at 16:16
  • Thanks Matt - why in _Launching & _Activated and not in the constructor? – tig Sep 08 '10 at 17:14
  • because otherwise it might not get re-initialised when the app returns from tombstoning –  Sep 26 '10 at 08:34