MVVM是wp7开发的一种设计模式,其目的也是为了将数据层(Model)与UI层(View)分开。ViewModel则是用来连接数据层与UI层的C#类。个人感觉,MVVM和MVC是差不多的。下面就用微软的sample code来理解下MVVM 设计模式。
这个例子是一个游戏成就的记录工具,分为两个部分:收集品成就,以及等级成就。
收集品成就 又分为药品数量,硬币数量,心数量。
等级成就 有1,2,3三个等级。
游戏效果如下
下面讲实现代码,先建立一个Silverlight for Windows Phone工程。
solution结构如下
建立Model层类
建立ViewModel层类
建立两个新View,ItemView.xaml(收集品的表示区域)和LevelView.xaml(等级的表示区域)
编辑ItemView.xaml,在GRID element里添加以下source
建立第二个view
在头部的UserControl增加以下代码。这里表示要引用MVVMTestApp.View的source。这里:src是自定义的tag名,也可以用别的命名。
下面调用BoolOpposite的时候要跟前缀src:。
xmlns:src="clr-namespace:MVVMTestApp.View"
在UserControl 和 GRID 之间, 增加以下代码,这里添加source的目的是增加一个Converter。
因为开发者认为等级成就完成后,是不能退回去的。也就是说当等级成就为false时,该等级是可编辑的。
但等级变成true以后就不能再编辑了。
<UserControl.Resources>
<src:BoolOpposite x:Key="BoolOpposite"/>
</UserControl.Resources>
在GRID element里添加以下source
这里,CheckBox是否钩上,以及能否编辑都与Completed属性绑定,但是能否编辑增加了反转Completed属性的Converter:BoolOpposite
<CheckBox x:Name="Completed" IsChecked="{Binding Path=Completed, Mode=TwoWay}" Grid.Column="1" HorizontalAlignment="Center" IsEnabled="{Binding Path=Completed, Converter={StaticResource BoolOpposite}}"/>
将第二个View里,UI层的对应代码替换如下:
编辑主View,在phone tag里添加一下代码:
xmlns:views="clr-namespace:MVVMTestApp.View"
在ContentPanel GRID element里,增加以下属性
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"></Grid>
替换ContentPanel GRID element 的默认代码如下
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<TextBlock Text="Items Collected" Foreground="{StaticResource PhoneAccentBrush}" Style="{StaticResource PhoneTextLargeStyle}" />
<views:ItemView x:Name="ItemViewOnPage" Height="200"/>
<TextBlock Text="Levels Completed" Foreground="{StaticResource PhoneAccentBrush}" Style="{StaticResource PhoneTextLargeStyle}" />
<views:LevelView x:Name="LevelViewOnPage" Height="200"/>
</StackPanel>
</Grid>
修改主View对应的UI层代码
增加一个类用以维护页面的状态。
修改App.xaml对应的Code,替换如下
主View 的对应Code,替换如下:
// Old instance of the application // The user started the application from the Back button. if (!StateUtilities.IsLaunching && this.State.ContainsKey("Accomplishments")) { vm = (ViewModel)this.State["Accomplishments"]; //MessageBox.Show("Got data from state"); } // New instance of the application // The user started the application from the application list, // or there is no saved state available. else { vm.GetAccomplishments(); //MessageBox.Show("Did not get data from state"); }
在OnNavigatedTo 函数后增加以下方法,当State里没有Accomplishments属性时,增添Accomplishments属性,否则替换它。
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedFrom(e); if (this.State.ContainsKey("Accomplishments")) { this.State["Accomplishments"] = vm; } else { this.State.Add("Accomplishments", vm); }增加application bar, OnNavigatedFrom method后面添加一下代码
在MainPage.xaml 里,把</phone:PhoneApplicationPage.ApplicationBar>-->替换如下:private void AppBarSave_Click(object sender, EventArgs e) { vm.SaveAccomplishments(); }<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" > <shell:ApplicationBarIconButton IconUri="AppBarSave.png" Text="Save" Click="AppBarSave_Click" /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>
完成!