[Silverlight]MVVM+MEF框架Jounce练习(1)
2012-12-01 09:55 slmk 阅读(1480) 评论(1) 编辑 收藏 举报光学不练,对一些概念的理解就只能停留在表面了。这个系列主要记录自己对Jounce框架的理解和测试代码,以加深对MVVM和Silverlight的一些概念的理解。本例主要测试Jounce框架中View和ViewModel的通信。
MVVM的优点
我认为Model、View和ViewModel的设计原则:模型、视图和视图模型分离,主要有两方面的优点:
1. 便于团队协作和单元测试。开发人员开发出适合业务逻辑的Model和ViewModel,并在没有View的情况下就可以做单元测试;美工人员根据ViewModel设计好View;测试人员可以只根据View、ViewModel或者Model其中之一的情况下写测试代码。还实现了更好的模块化,尽管有时我们都是一个人在做这些事情。
2.XAML系的特点,采用MVVM的模式,可以减少很多繁琐的界面更新的代码,例如对象属性改变后,在ViewModel中调用适当的方法,就可以完成界面的更新,这样我们可以更多的关心业务逻辑。相对于传统的Winforms,更适合采用这种设计模式。
思维方式的改变
我以前直接在View的后台代码里,想怎么控制界面都可以。现在MVVM了,给我整分离了,ViewModel和View不能相互引用对方,两者如何通讯呢?例如我点击Save按钮,想要显示一个等待界面给用户:以前多方便,直接调用一个等待界面代码即可。现在呢?点击事件抽象成Command,绑定由ViewModel来处理,而ViewModel不能引用View,又如何改变View的状态呢?Jounce又是如何做到的呢?我们想达到的是这种效果:
可以有两种方法:
1. 利用View和ViewModel的契约
这种契约其实就是绑定,View界面元素的属性绑定到ViewModel的属性上,这样就形成了一种约定:ViewModel的属性会影响元素显示,反过来也一样(如果是双向绑定)。
View代码可以这样写:
<Grid x:Name="LayoutRoot" Background="White"> <StackPanel x:Name="Sp"> <TextBlock FontSize="36" Text="{Binding Welcome}"/> <Button Width="100" Margin="4" Content="Save" Command="{Binding SaveCommand}"/> </StackPanel> <TextBlock Text="正在保存..." Visibility="{Binding IsSaving}" Foreground="Blue" Height="50" x:Name="tbSaving" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid>
ViewModel这样写:
[ExportAsViewModel(typeof (MainViewModel))] public class MainViewModel : BaseViewModel { public MainViewModel() { SaveCommand = new ActionCommand<object>(o => { IsSaving = Visibility.Visible; }); } public string Welcome { get { return InDesigner ? "Jounce Design-time View" : "Welcome to Jounce."; } } public IActionCommand<object> SaveCommand { get; set; } Visibility _isSaving=Visibility.Collapsed; public Visibility IsSaving { get { return _isSaving; } set { _isSaving = value; RaisePropertyChanged("IsSaving"); } } }
Jounce的BaseViewModel实现了INotifyPropertyChanged接口,通过调用RaisePropertyChanged方法可以在属性改变时,通知界面更新。
为了简单,这里实现的很简陋,比较优雅的实现可以使用BusyIndicator控件。
2.利用Jounce的GoToVisualState
Jounce的BaseViewModel提供了GoToVisualState方法,可以在不引用View的情况下改变View的状态。
View代码:
<Grid x:Name="LayoutRoot" Background="White"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="Commstates"> <VisualState x:Name="Normal"/> <VisualState x:Name="Saving"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="tbSaving" Storyboard.TargetProperty="Opacity" To="1"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <StackPanel x:Name="Sp"> <TextBlock FontSize="24" Text="{Binding Welcome}"/> <Button Width="100" Margin="4" Content="Save" Command="{Binding SaveCommand}"/> </StackPanel> <TextBlock Text="正在保存..." Foreground="Blue" Height="50" x:Name="tbSaving" Opacity="0" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid>
ViewModel代码:
public MainViewModel() { SaveCommand = new ActionCommand<object>(o =>{
GoToVisualState("Saving", true);
});
}
参考: