最近面试多次被问及MVVM,虽然看过园子里的教程,毕竟未实际实现过,都回答“只了解,未实践过”。今天终于逼自己去用MVVM重构下这个应用。
这里就不多说MVVM的理论等东西了。需要了解的搜一下园子吧,大把大把的!
这次我选择了MVVM Light框架去实现MVVM。我也没用过其他的框架,也不知道有什么特别的地方或者优势,使用MVVM Light也全听别人说不错。
首先去codeplex下载下来MVVM Light:http://mvvmlight.codeplex.com/ 安装之。安装完成之后在原来的项目上添加引用:
调整项目目录结构:
新建View,ViewModel两个文件夹。把ChannelTile.xaml,MainPage.xaml移动到View文件夹下。在ViewModel文件夹下右键新建类,选择MVVM Light为我们提供的模板:MvvmViewModel(wp7)。
新建一个叫ChannelTileViewModel的类。把原来在ChannelTile.cs文件里的代码移植了一部分过来。
using GalaSoft.MvvmLight;
using Microsoft.Xna.Framework.Input.Touch;
using Helper;
using System;
using System.Windows;
namespace DBFM7.ViewModel
{
/// <summary>
/// This class contains properties that a View can data bind to.
/// <para>
/// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
/// </para>
/// <para>
/// See http://www.galasoft.ch/mvvm/getstarted
/// </para>
/// </summary>
public class ChannelTileViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the ChannelTileViewModel class.
/// </summary>
public ChannelTileViewModel()
{
TouchPanel.EnabledGestures = GestureType.Tap | GestureType.HorizontalDrag;
if (!PlayListHelper.IsInited)
{
PlayListHelper.InitChannelComplete += new Action(PlayListHelper_InitChannelComplete);
PlayListHelper.InitChannel();//初始化播放列表
}
else
this.IsShowGoBtn = Visibility.Visible;
}
private string _Title="频道正在初始化...";
/// <summary>
/// 标题
/// </summary>
public string Title
{ get { return _Title; }
set
{
this._Title = value;
this.RaisePropertyChanged("Title");
}
}
private Visibility _IsShowGoBtn=Visibility.Collapsed;
/// <summary>
/// 是否显示右边的箭头
/// </summary>
public Visibility IsShowGoBtn
{
get { return this._IsShowGoBtn; }
set
{
this._IsShowGoBtn = value;
this.RaisePropertyChanged("IsShowGoBtn");
}
}
/// <summary>
/// 初始化tile的image跟title
/// </summary>
protected void PlayListHelper_InitChannelComplete()
{
this.Title = "请选择一个你喜欢的频道";
}
}
}
这个类继承ViewModelBase,它已经帮我们实现了INotifyPropertyChanged接口,所以简化了实现ViewModelBase的步骤。我们只要定义一个属性,然后在set方法里调用RaisePropertyChanged()方法就实现了依赖属性。
然后在项目目录下新建一个MvvmViewModelLocator,还是使用MVVM Light的模板:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using DBFM7.ViewModel;
namespace DBFM7
{
/// <summary>
/// This class contains static references to all the view models in the
/// application and provides an entry point for the bindings.
/// <para>
/// Use the <strong>mvvmlocatorproperty</strong> snippet to add ViewModels
/// to this locator.
/// </para>
/// <para>
/// See http://www.galasoft.ch/mvvm/getstarted
/// </para>
/// </summary>
public class MvvmViewModelLocator
{
static MvvmViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
// SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
}
else
{
// SimpleIoc.Default.Register<IDataService, DataService>();
}
SimpleIoc.Default.Register<ChannelTileViewModel>();
}
/// <summary>
/// Gets the Main property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public ChannelTileViewModel ChannelTile
{
get
{
return ServiceLocator.Current.GetInstance<ChannelTileViewModel>();
}
}
}
}
把生成的MainViewModel替换成ChannelTileViewModel。
在APP.Xaml添加一个静态资源:
<Application.Resources>
<vm:MvvmViewModelLocator xmlns:vm="clr-namespace:DBFM7"
x:Key="Locator" />
</Application.Resources>
把ChannelTileViewModel跟ChannelTile.xaml绑定起来。
<phone:PhoneApplicationPage xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
x:Class="DBFM7.View.ChannelTile"
。。。。。。。。。。。。
DataContext="{Binding ChannelTile,Source={StaticResource Locator}}">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,0">
<TextBlock x:Name="ApplicationTitle" Text="DB.FM 7" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock HorizontalAlignment="Center" x:Name="PageTitle"
Text="{Binding Title}"
Margin="0,40,0,0" FontSize="22"/>
</StackPanel>
。。。。。。。。。。。。。。。。。。
<Image Grid.Column="2"
VerticalAlignment="Top"
Margin="0,12,0,0"
Width="48" Height="48"
Source="..\ICON\RightGo.png"
x:Name="imgGo" Tap="imgGo_Tap"
Visibility="{Binding IsShowGoBtn}" />
这样就用MVVM Light基本实现了数据绑定的功能。