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?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…