? ? ? ?
在WPF開發(fā)中,經(jīng)典的編程模式是MVVM,是為WPF量身定做的模式,該模式充分利用了WPF的數(shù)據(jù)綁定機制,最大限度地降低了Xmal文件和CS文件的耦合度,也就是UI顯示和邏輯代碼的耦合度,如需要更換界面時,邏輯代碼修改很少,甚至不用修改。與WinForm開發(fā)相比,我們一般在后置代碼中會使用控件的名字來操作控件的屬性來更新UI,而在WPF中通常是通過數(shù)據(jù)綁定來更新UI;在響應(yīng)用戶操作上,WinForm是通過控件的事件來處理,而WPF可以使用命令綁定的方式來處理,耦合度將降低,WPF技術(shù)的主要特點是數(shù)據(jù)驅(qū)動UI,所以在使用WPF技術(shù)開發(fā)的過程中是以數(shù)據(jù)為核心的,WPF提供了數(shù)據(jù)綁定機制,當(dāng)數(shù)據(jù)發(fā)生變化時,WPF會自動發(fā)出通知去更新UI。本教程的第15到19簡單介紹了數(shù)據(jù)綁定的簡單應(yīng)用
一、MVVM介紹
MVVM是Model-View-ViewModel(模型-視圖-視圖模型)的縮寫形式,它通常被用于WPF或Silverlight開發(fā)。我們可以通過下圖來直觀的理解MVVM模式:
1、View就是xaml界面,也就是那個擴展名為xaml的文件,它負責(zé)與用戶交互,接收用戶輸入,把數(shù)據(jù)展現(xiàn)給用戶。
2、ViewModel就是一個C#類,負責(zé)收集需要綁定的數(shù)據(jù)和命令,通過View類的DataContext屬性綁定到View,同時也可以處理一些UI邏輯。
3、Model,就是數(shù)據(jù)庫系統(tǒng)中的實體對象,可包含屬性和行為。
三者之間的關(guān)系:View對應(yīng)一個ViewModel,ViewModel可以聚合N個Model,ViewModel可以對應(yīng)多個View
二、MVVM的優(yōu)勢
??????MVVM的根本思想就是界面和業(yè)務(wù)功能進行分離,View的職責(zé)就是負責(zé)如何顯示數(shù)據(jù)及發(fā)送命令,ViewModel的功能就是如何提供數(shù)據(jù)和執(zhí)行命令。各司其職,互不影響。在實際的業(yè)務(wù)場景中我們經(jīng)常會遇到客戶對界面提出建議要求修改,使用MVVM模式開發(fā),當(dāng)設(shè)計的界面不滿足客戶時,我們僅僅只需要對View作修改,不會影響到ViewModel中的功能代碼,減少了犯錯的機會。隨著功能地增加,系統(tǒng)越來越復(fù)雜,相應(yīng)地程序中會增加View和ViewModel文件,將復(fù)雜的界面分離成局部的View,局部的View對應(yīng)局部的ViewModel,功能點散落在各個ViewModel中,每個ViewModel只專注自己職能之內(nèi)的事情。ViewModel包含了View要顯示的數(shù)據(jù),并且知道View的交互代碼,使用MVVM架構(gòu)具有以下優(yōu)勢:
1、易維護?2、靈活擴展??3、易測試??4、用戶界面設(shè)計師與程序開發(fā)者能更好的合作
三、MVVM簡單示例
1、在項目的model文件創(chuàng)建類Emp及EmpViewModel,內(nèi)容如下:
注意這個EmpViewModel叫“視圖模型”,通過數(shù)據(jù)綁定將它們綁在一起,它真的是一個很好的適配器能將模型變成某種WPF框架可以使用的東西。所以這個就是MVVM中的VM,而Emp是M,同在缺少V。
2、在control文件夾中添加窗口MVVMWindow1.xaml,具體內(nèi)容如下:
<Window x:Class="WpfApp6.control.MVVMWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp6.control"
xmlns:vm="clr-namespace:WpfApp6.model"
mc:Ignorable="d"
Title="MVVM簡單介紹" Height="450" Width="800">
<!--窗口的上下文聲明一個EmpViewModel的實例,前面必須定義vm這個命名空間-->
<Window.DataContext>
<vm:EmpViewModel></vm:EmpViewModel>
</Window.DataContext>
<Window.Resources>
<!--聲明樣式-->
<Style x:Key="st1">
<Setter Property="Control.FontSize" Value="17"></Setter>
</Style>
</Window.Resources>
<Grid Style="{StaticResource st1}" >
<Button Content="更新" HorizontalAlignment="Left" Margin="180,256,0,0" VerticalAlignment="Top" Width="145" Click="Button_Click"/>
<Label Content="用戶:" HorizontalAlignment="Left" Margin="112,110,0,0" VerticalAlignment="Top" RenderTransformOrigin="7.256,0.582"/>
<!--Binding綁定視圖模型中的UserName和CompanyName-->
<TextBox HorizontalAlignment="Left" Height="23" Margin="205,110,0,0" TextWrapping="Wrap" Text="{Binding UserName}" VerticalAlignment="Top" Width="120"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="555,110,0,0" TextWrapping="Wrap" Text="{Binding CompanyName}" VerticalAlignment="Top" Width="120"/>
<Label Content="公司:" HorizontalAlignment="Left" Margin="393,110,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>
?3、MVVMWindow1.xaml.cs后臺代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WpfApp6.model;
namespace WpfApp6.control
{
/// <summary>
/// MVVMWindow1.xaml 的交互邏輯
/// </summary>
public partial class MVVMWindow1 : Window
{
EmpViewModel empvm ;
public MVVMWindow1()
{
InitializeComponent();
empvm = base.DataContext as EmpViewModel;
}
/// <summary>
/// 單擊按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_Click(object sender, RoutedEventArgs e)
{
empvm.UserName = "歐陽克";
empvm.CompanyName = "華山莊";
}
}
}
?4、啟動程序,記得將項目啟動文件App.xaml中的啟動項改為?StartupUri="control/MVVMWindow1.xaml",運行結(jié)果,點擊按鈕時,不會有任何反應(yīng)
?這里我們點擊更新按鈕不會有任何反應(yīng),因為還沒有實現(xiàn)數(shù)據(jù)綁定。此時視圖不會收到任何的關(guān)于屬性改變的通知。要解決這個問題我們必須實現(xiàn)名稱為INotifyPropertyChanged的接口。任何實現(xiàn)了這個接口的類,當(dāng)屬性發(fā)生改變的時候會通知所有監(jiān)聽者,所以我們需要修改視圖模型NameViewModel類,完整代碼是:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp6.model
{
/// <summary>
/// 頁面視圖模型,實現(xiàn)INotifyPropertyChanged接口
/// </summary>
public class EmpViewModel:INotifyPropertyChanged
{
//構(gòu)造方法
public EmpViewModel()
{
emp = new Emp() { UserName = "楊康", CompanyName = "上海金財" };
}
//私有字段
private Emp emp;
//公共屬性
public string UserName
{
get { return emp.UserName; }
set { emp.UserName = value;RaisePropertyChanged("UserName"); }
}
// 屬性值發(fā)生更改時觸發(fā)的屬性
public event PropertyChangedEventHandler PropertyChanged;
//屬性更改方法
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public string CompanyName
{
get { return emp.CompanyName; }
set { emp.CompanyName = value; RaisePropertyChanged("CompanyName"); }
}
}
}
注意視圖模型類實現(xiàn)了INotifyPropertyChanged接口,即通知屬性更改,每個屬性中增加了代碼RaisePropertyChanged,這個方法就是屬性更改時的方法,并且定義了一個事件屬性,即public event PropertyChangedEventHandler PropertyChanged;其他代碼沒有變,運行后,點擊更新效果是:
?
?這里說明UI同步更新了,關(guān)鍵在于INotifyPropertyChanged,但是上面的方法還有不足,那就是假如有多個model需要設(shè)置屬性更改,那工作量是蠻麻煩和巨大的,這里需要改進方法,定義一個基類,讓基類實現(xiàn)INotifyPropertyChanged,讓用戶類繼續(xù)基類,具體操作是:
5、在model中添加類ViewModelBase,代碼是:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp6.model
{
/// <summary>
/// 模型視圖其類
/// </summary>
public class ViewModelBase : INotifyPropertyChanged
{
/// <summary>
/// 屬性值發(fā)生更改時觸發(fā)
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// 執(zhí)行更改
/// C#5.0中的新特性CallerMemberName
/// </summary>
/// <param name="propertyName"></param>
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
6、在model創(chuàng)建另一個類,EmpViewModel2,代碼?是:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp6.model
{
/// <summary>
/// 繼承基類ViewModelBase
/// </summary>
public class EmpViewModel2:ViewModelBase
{
public EmpViewModel2()
{
emp = new Emp() { UserName = "楊康", CompanyName = "上海金財" };
}
//私有字段
private Emp emp;
//公共屬性
public string UserName
{
get { return emp.UserName; }
set {
emp.UserName = value;
OnPropertyChanged();
}
}
public string CompanyName
{
get { return emp.CompanyName; }
set {
emp.CompanyName = value;
OnPropertyChanged();
}
}
}
}
?6、修改MVVMWindow1.xaml文件的一個地方,即改成以下內(nèi)容,表示現(xiàn)在窗口的上下文使用EmpViewModel2,也就是上面第5步的視圖模型,而不是原來的EmpViewModel,其他都不要改
??
?7、修改MVVMWindow1.xaml.cs代碼,如圖
?
?8、運行程序,效果如下:
?小結(jié),我們在實際項目中應(yīng)該使用后面定義基類的方式去實現(xiàn)屬性的綁定,這才是對的。文章來源:http://www.zghlxwxcb.cn/news/detail-774174.html
操作起來6666,棒棒噠。文章來源地址http://www.zghlxwxcb.cn/news/detail-774174.html
到了這里,關(guān)于WPF真入門教程23--MVVM簡單介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!