MVVM模式構架分爲視圖層V、視圖模型層VM、模型層M,View主要用於界面呈現,ViewModel用於邏輯實現,Model用於數據的構造,而這三者能夠進行通信,對於簡單的應用大規模運用MVVM模式開始可能會降低開發效率,但Silverlight提供了強大的數據綁定機制,將View和ViewModel有效的聯繫起來,會大大提高開發效率,特別較爲複雜的應用,MVVM模式並有助於應用程序的測試、維護和升級,使得設計人員專注於界面設計,開發人員專注於代碼,他們並能很好的合作。
Model 是應用程序的核心,代表着最大、最重要的業務資產,因爲它記錄了所有複雜的業務實體、它們之間的關係以及它們的功能。Model 之上是 ViewModel。ViewModel 的兩個主要目標分別是:使 Model 能夠輕鬆被 WPF/XAML View 使用;將 Model 從 View 分離並對 Model 進行封裝。這些目標當然非常好,但是由於一些現實的原因,有時並不能達到這些目標。
您構建的 ViewModel 知道用戶在高層上將如何與應用程序交互。但是,ViewModel 對 View 一無所知,這是 MVVM 設計模式的重要部分。這使得交互設計師和圖形設計師能夠在 ViewModel 的基礎上創建優美、有效的 UI,同時與開發人員密切配合,設計適當的 ViewModel 來支持其工作。此外,View 與 ViewModel 的分離還使得 ViewModel 更有利於單元測試和重用。
MVVM 模式中存在三個核心組件:模型、視圖和視圖模型。除了瞭解這三個組件的作用,還要了解這些組件相互之間如何交互,這也很重要。從最高層面上來說,視圖“瞭解”視圖模型,視圖模型“瞭解”模型,但模型不瞭解視圖模型,視圖模型不瞭解視圖,下圖 演示了這三個組件之間的關係
Model 是應用程序的核心,代表着最大、最重要的業務資產,因爲它記錄了所有複雜的業務實體、它們之間的關係以及它們的功能。Model 之上是 ViewModel。ViewModel 的兩個主要目標分別是:使 Model 能夠輕鬆被 WPF/XAML View 使用;將 Model 從 View 分離並對 Model 進行封裝。這些目標當然非常好,但是由於一些現實的原因,有時並不能達到這些目標。
您構建的 ViewModel 知道用戶在高層上將如何與應用程序交互。但是,ViewModel 對 View 一無所知,這是 MVVM 設計模式的重要部分。這使得交互設計師和圖形設計師能夠在 ViewModel 的基礎上創建優美、有效的 UI,同時與開發人員密切配合,設計適當的 ViewModel 來支持其工作。此外,View 與 ViewModel 的分離還使得 ViewModel 更有利於單元測試和重用。
MVVM 模式中存在三個核心組件:模型、視圖和視圖模型。除了瞭解這三個組件的作用,還要了解這些組件相互之間如何交互,這也很重要。從最高層面上來說,視圖“瞭解”視圖模型,視圖模型“瞭解”模型,但模型不瞭解視圖模型,視圖模型不瞭解視圖,下圖 演示了這三個組件之間的關係
是在 MVVM 模式中清楚地劃分職責的一些好處:
• 在開發過程中,開發人員和設計人員可以更好地獨立和並行處理各自的組件。設計人員可將精力集中在視圖上,如果他們使用的是 Expression Blend,則可以輕鬆生成要處理的示例數據,而開發人員可處理視圖模型和模型組件。
• 開發人員可爲視圖模型和模型創建單元測試而不使用視圖。視圖模型的單元測試可準確地執行視圖使用的相同功能。
• 由於視圖完全在 XAML 中實現,因此可以輕鬆地重新設計應用程序 UI 而不必改動代碼。新版本的視圖應可以與現有視圖模型一起使用。
• 如果現有的模型實現封裝了現有業務邏輯,則更改起來可能存在難度或風險。在這種情況下,視圖模型將充當模型類的適配器,您可以通過它避免對模型代碼做出重大更改。
一Model模型層
Model模型層是一個面向對象的實體類。如:
首先在Student.cs中簡單聲明瞭一個類
public class Student
{
public string name { get; set;}
public int age { get; set; }
public string class { get; set;}
}
類型定義好後,我們在Students.cs中得到一個Student的集合
public class Students
{
public List<Student> listStudent;
public List<Student> GetStudentS()
{
listStudent = new List<Student>()
{
new Student {name = "Tom", age = 21,Class=”一年級二班” },
new Student {name = "Jack", age = 22 ,Class=”一年級二班”},
new Student {name = "Rose", age = 23 ,Class=”一年級二班”},
};
return listStudent;
}
}
Model模型層是一個面向對象的實體類。如:
首先在Student.cs中簡單聲明瞭一個類
public class Student
{
public string name { get; set;}
public int age { get; set; }
public string class { get; set;}
}
類型定義好後,我們在Students.cs中得到一個Student的集合
public class Students
{
public List<Student> listStudent;
public List<Student> GetStudentS()
{
listStudent = new List<Student>()
{
new Student {name = "Tom", age = 21,Class=”一年級二班” },
new Student {name = "Jack", age = 22 ,Class=”一年級二班”},
new Student {name = "Rose", age = 23 ,Class=”一年級二班”},
};
return listStudent;
}
}
二、ViewModel視圖模型層
ViewModel是視圖模型層 這一層是對View視圖層展現、數據的讀取以及各種事件的處理。如:
public class ViewModel
{
public List<Students> vStudents { get; set; }
public ViewModel()
{
vStudents = new Students ().GetStudentS ();
}
}
ViewModel是視圖模型層 這一層是對View視圖層展現、數據的讀取以及各種事件的處理。如:
public class ViewModel
{
public List<Students> vStudents { get; set; }
public ViewModel()
{
vStudents = new Students ().GetStudentS ();
}
}
Command命令一般都需要定義成獨立的類來實現,然後再ViewModel上實例化
Command命令類的實現的方法可以繼承ICommand 使用第三方組件的Command命令的類
繼承ICommand 的語法如下
public class MyCommand<T> : ICommand
{
Action<T> Excuted;
Func<bool> canExcute;
public ShowMessageCommand(Action<T> excuted)
{
this.Excuted = excuted;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
//你的需要執行的代碼
}
}
Command命令類的實現的方法可以繼承ICommand 使用第三方組件的Command命令的類
繼承ICommand 的語法如下
public class MyCommand<T> : ICommand
{
Action<T> Excuted;
Func<bool> canExcute;
public ShowMessageCommand(Action<T> excuted)
{
this.Excuted = excuted;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
//你的需要執行的代碼
}
}
三、View視圖層
View視圖層是界面的設計,文件表現爲xaml文件。
先在應用程序中定義爲資源:
<Application.Resources>
<vmmodel: ViewModel x:Key=" vStudents "></vmmodel: ViewModel>
</ Application.Resources>
也可在具體頁中定義。
<UserControl.Resources>
<vmmodel: ViewModel x:Key=" vStudents "></vmmodel: ViewModel>
<UserControl.Resources>
View視圖層是界面的設計,文件表現爲xaml文件。
先在應用程序中定義爲資源:
<Application.Resources>
<vmmodel: ViewModel x:Key=" vStudents "></vmmodel: ViewModel>
</ Application.Resources>
也可在具體頁中定義。
<UserControl.Resources>
<vmmodel: ViewModel x:Key=" vStudents "></vmmodel: ViewModel>
<UserControl.Resources>
頁面引用:
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource vStudents }" >
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource vStudents }" >
實現綁定:
<DataTemplate>
<StackPanel>
<TextBlock HorizontalAlignment="Left" Name="textBlock1" Text="{Binding name}" VerticalAlignment="Top" />
<TextBlock HorizontalAlignment="Left" Name="textBlock2" Text="{Binding age}" VerticalAlignment="Top" />
<TextBlock HorizontalAlignment="Left" Name="textBlock2" Text="{Binding Class}" VerticalAlignment="Top" />
</StackPanel>
</DataTemplate>
案例6:MVVM模式
這是一個MVVM模式,在前面的講解的基礎上,實現更多的功能, MVVM模式重點是實現綁定,而其中的難點是命令綁定,下面舉例說明命令綁定的實現。該例實現一個矩形的放大縮小。
(1) 新建一個Windows Phone Project。創建Command、ViewModel二個文件夾,用於創建對應於的文件,此類功能簡單Model層不必創建、View層就直接用MainPage.xaml。
(2)在Model目錄下創建類ExecuteCommandAction.cs,以便在首頁實現綁定,主要代碼如下:
public class ExecuteCommandAction:TriggerAction<FrameworkElement>
{
public static readonly DependencyProperty CommandNameProperty =
DependencyProperty.Register("CommandName", typeof(string), typeof(ExecuteCommandAction), null);
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(ExecuteCommandAction), null);
protected override void Invoke(object parameter)
{
if (AssociatedObject == null)
return;
ICommand command = null;
var dataContext = AssociatedObject.DataContext;//調用視圖的上下文Content
foreach (var info in dataContext.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (IsCommandProperty(info) && String.Equals(info.Name, CommandName, StringComparison.Ordinal))//找到命爲"AddRadius"的ICommand:AddRadius
{
command = (ICommand)info.GetValue(dataContext, null);
break;
}
}
if ((command != null) && command.CanExecute(CommandParameter))
{
command.Execute(CommandParameter);//運行AddRadius,AddRadius命令內容就是增加半徑
}
}
private static bool IsCommandProperty(PropertyInfo property)
{
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(ExecuteCommandAction), null);
protected override void Invoke(object parameter)
{
if (AssociatedObject == null)
return;
ICommand command = null;
var dataContext = AssociatedObject.DataContext;//調用視圖的上下文Content
foreach (var info in dataContext.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (IsCommandProperty(info) && String.Equals(info.Name, CommandName, StringComparison.Ordinal))//找到命爲"AddRadius"的ICommand:AddRadius
{
command = (ICommand)info.GetValue(dataContext, null);
break;
}
}
if ((command != null) && command.CanExecute(CommandParameter))
{
command.Execute(CommandParameter);//運行AddRadius,AddRadius命令內容就是增加半徑
}
}
private static bool IsCommandProperty(PropertyInfo property)
{
return typeof(ICommand).IsAssignableFrom(property.PropertyType);
}
(3)在ViewModel目錄下創建視圖模型類:
public class RadiusViewModel : INotifyPropertyChanged
{
private Double radius;
public RadiusViewModel()
{
Radius = 0;
AddRadius = new ActionCommand(p => Radius += 50);
ShuRadius = new ActionCommand(p => Radius -= 10);
}
public event PropertyChangedEventHandler PropertyChanged;
public ICommand AddRadius
{
get;
private set;
}
public ICommand ShuRadius
{
get;
private set;
}
public Double Radius
{
get
{
return radius;
}
set
{
{
private Double radius;
public RadiusViewModel()
{
Radius = 0;
AddRadius = new ActionCommand(p => Radius += 50);
ShuRadius = new ActionCommand(p => Radius -= 10);
}
public event PropertyChangedEventHandler PropertyChanged;
public ICommand AddRadius
{
get;
private set;
}
public ICommand ShuRadius
{
get;
private set;
}
public Double Radius
{
get
{
return radius;
}
set
{
radius = value;
OnPropertyChanged("Radius");
}
}
(5)在首頁MainPage創建RadiusViewModel實體,聲明爲資源,在頁面長方形的寬、高綁定其中的屬性Radius:
<!--設置整個頁面DataContext爲視圖模型類RadiusViewModel-->
(5)在首頁MainPage創建RadiusViewModel實體,聲明爲資源,在頁面長方形的寬、高綁定其中的屬性Radius:
<!--設置整個頁面DataContext爲視圖模型類RadiusViewModel-->
<phone:PhoneApplicationPage.DataContext>
<my:RadiusViewModel/>
</phone:PhoneApplicationPage.DataContext>
<Rectangle Fill="Blue"
Height="{Binding Radius}" Width="{Binding Radius}"
<my:RadiusViewModel/>
</phone:PhoneApplicationPage.DataContext>
<Rectangle Fill="Blue"
Height="{Binding Radius}" Width="{Binding Radius}"
HorizontalAlignment="Left" Margin="71,78,0,0" Name="ellipse1" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" />
(6) 綁定命令,實現放大、縮小的功能
<Button Content="放大" Height="72" HorizontalAlignment="Left" Margin="71,468,0,0" Name="button2" VerticalAlignment="Top" Width="160" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="Click">
<my_Interactivity:ExecuteCommandAction CommandName="AddRadius"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
</Button>
<Button Content="縮小" Height="72" HorizontalAlignment="Left" Margin="253,468,0,0" Name="button3" VerticalAlignment="Top" Width="160" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="Click">
<my_Interactivity:ExecuteCommandAction CommandName="ShuRadius"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
</Button>
運行,可看到如下效果:
這是一個簡單案例,主要實現了一個命令綁定,實際應用中可能更復雜,按照MVVM模式的思想編寫的程序應該拋棄Xaml文件的code behind(即xaml.cs)文件,這樣才能讓開發和設計各盡其能,MVVM模式的View與ViewModel有三大通訊方式:Binding Data(實現數據的傳遞)、Command(實現操作的調用)和Attached Behavior(實現控件加載過程中的操作)。
在www.CodePlex.com上有許多不錯的第三方MVVM框架可供我們借鑑和使用,較常用的有下面兩個:
MVVM Light Toolkit是幫助人們在Silverlight和WPF中使用MVVM設計模式的一套組件。它是一個輕量級的、務實的框架,只包含所需的必要組成部分。
下載地址: http://mvvmlight.codeplex.com/ 。
Simple MVVM Toolkit使開發應用MVVM設計模式Widnows Phone的應用程序變得更容易,爲基於 MVVM設計模式的應用程序提供一個簡單的框架和工具集。Simple MVVM Toolkit的特點是簡單,但它包含執行 MVVM 設計模式的應用程序所需的一切。
下載地址: http://simplemvvmtoolkit.codeplex.com/ 。