MVVM(Model-View-ViewModel)是xaml开发者常用的装逼模式,WP应用也不例外,除了我们常用的Prism和MVVM Light,现在还有个后起之秀叫做MVVM-Sidekick。用了它,就可以充分利用.NET4.5的async await来提升逼格了,这个轻量级框架也提供了非常便捷的代码模板,同样完成一个功能需要花费的精力比同类框架要少。具体介绍可以看它的官网:https://github.com/waynebaby/mvvM-Sidekick
但是,在DataContext的处理上,这个框架有些特殊。前几天我就爆掉了。
简单的说,我的需求就是在Windows Phone页面上显示一个进度指示器,把后台的Busy和Message属性绑定到ProgressIndicator上面。这个简单的任务在MVVM Light框架中与其他UI控件的绑定完全一致,可以这么写:
<shell:SystemTray.ProgressIndicator>
<shell:ProgressIndicator
IsIndeterminate="{Binding Busy}"
IsVisible="{Binding Busy}"
Text="{Binding Message}" />
</shell:SystemTray.ProgressIndicator>
后台代码:
public MainViewModel()
{
_ShowProgressBar = new RelayCommand(() => ShowProgressBar());
_HideProgressBar = new RelayCommand(() => HideProgressBar());
}
private bool _busy;
public bool Busy
{
get { return _busy; }
set { _busy = value; RaisePropertyChanged("Busy"); }
}
private string _Message;
public string Message
{
get { return _Message; }
set { _Message = value; RaisePropertyChanged("Message"); }
}
public RelayCommand _ShowProgressBar { get; set; }
private void ShowProgressBar()
{
Busy = true;
Message = "Loading...";
}
public RelayCommand _HideProgressBar { get; set; }
private void HideProgressBar()
{
Busy = false;
Message = string.Empty;
}
然而xaml的这段代码在MVVM-Sidekick下是不起作用的。编译不会报错,运行也不会报错,就是没有效果。很明显是DataContext不对。
稍微看了下发现MVVM-Sidekick的DataContext是在LayoutGrid上的:
<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{StaticResource DesignVm}" >
...
如果你尝试用ElementName去做,也是不行的:
{Binding DataContext.Busy, ElementName=LayoutRoot}
其实思路没错,最关键的一步是要把ProgressIndicator定义在Resources里面(这个是我和框架作者神交之后得知的),虽然我也不知道为什么要这么弄,但觉得很牛逼的样子。
完整的代码:
<mvvm:MVVMPage ....
....
<mvvm:MVVMPage.Resources>
<vm:MovieListView_Model x:Key="DesignVm" />
<shell:ProgressIndicator x:Key="idk"
IsVisible="{Binding DataContext.Busy, ElementName=LayoutRoot}"
IsIndeterminate="{Binding DataContext.Busy, ElementName=LayoutRoot}"
Text="{Binding DataContext.Message, ElementName=LayoutRoot}" />
</mvvm:MVVMPage.Resources>
<shell:SystemTray.ProgressIndicator>
<Binding Source="{StaticResource idk}"/>
</shell:SystemTray.ProgressIndicator>
这个是100%可以成功的。有图有真相:

如果不定义在Resource里,而把Source指定为StaticResource DesignVm的话,只能在独立页面上work,如果你的页面是被navitgateTo的,还是会爆的。所以不要用下面这种写法。
<shell:SystemTray.ProgressIndicator>
<shell:ProgressIndicator IsVisible="{Binding Busy, Source={StaticResource DesignVm}}"
IsIndeterminate="{Binding Busy, Source={StaticResource DesignVm}}"
Text="{Binding Message, Source={StaticResource DesignVm}}" />
</shell:SystemTray.ProgressIndicator>