MVVM是一個比較熱門的開發框架,盡管已經出現很久了,仍然比較受歡迎。MVVM框架包括:
M:Model;Model指的是數據模型,例如你要在頁面展示聯系人信息,那麼Model就是聯系人的模型,包括聯系人的名字,電話號碼,頭像等。。。
V:View;View指的是展示的頁面,比如你所現在看到的這篇文章都是View。
VM:ViewModel;ViewModel指的是對View的抽象!什麼是抽象? 大概就是它實際是存在的,但你又不能直接"看"到。
對於這三者的關系,我舉個簡單的例子吧:
假設你喜歡一個姑娘,姑娘都有身高,體重,臉蛋類型等等對吧.
public class 姑娘
{
public enum 臉蛋類型
{
光滑 = 0,
麻子 = 1
}
public string 姓名 { get; set; }
public double 身高 { get; set; }
public double 體重 { get; set; }
public 臉蛋類型 臉蛋 { get; set; }
}
光有姑娘的概念不行呀,你要的是一個實例,那好,咱new一個
private 姑娘 我的姑娘 = new 姑娘 { 體重 = 200, 姓名 = "狗蛋", 臉蛋 = 臉蛋類型.麻子, 身高 = 150 ,IsLike=false};//私有
你一看,臥槽這哪行,趕快滾蛋,重新new一個
private 姑娘 我的姑娘 = new 姑娘 { 體重 = 100, 姓名 = "柳言", 臉蛋 = 臉蛋類型.光滑, 身高 = 165,IsLike=true };
喜歡的姑娘有了,但你不知道姑娘是不是也喜歡你呀,所以你想對姑娘表達愛慕,看看姑娘的反應:
private async Task 表達愛慕()
{
string 騷話 = "騷話不斷,我宣你!";
try
{
var 她喜歡我 = await Say(騷話, 我的姑娘);
var 心情 = 她喜歡我 ? "得意洋洋" : "哭天搶地";
}
catch
{
Debug.WriteLine("革命尚未成功,同志仍需努力!");
}
}
private async Task<bool> Say(string _word, 姑娘 _girl)
{
//此處說完
await Task.Delay(10000);//姑娘很矜持
Random R = new Random();
var res= R.Next(0, 1);
switch (res)
{
case 1:
return true;
default:
return false;
}
}
上面的姑娘類就是Model,new的姑娘對象和表達愛慕就是ViewModel,你看到姑娘和姑娘給你的反饋就是View。
好了,現在說正經的:
在正式講MVVM之前先講幾個重要的知識:Binding,DataContext,INotifyPropertyChanged接口
Binding就是數據的綁定啦,比如你要展示上面姑娘的信息:
<StackPanel x:Name="profile_SP">
<TextBlock Text="{Binding 身高,Mode=OneWay}"/>
<TextBlock Text="{Binding 體重,Mode=TwoWay}"/>
</StackPanel>
Binding的Mode有三種:OneTime;OneWay,TowWay。OneTime表示綁定這個值以後無法更改;OneWay表示後台的更改前台同步顯示,但前台的更改後台不會發生改變,只會改變前台的顯示;TwoWay表示無論在哪裡的更改都是有效的。默認OneWay
這裡的身高和體重就是Binding的Path,Binding還有一個Source屬性,這裡沒有指定,但是在後台需是要指定,不然找不到身高和體重這兩個屬性了。Binding找數據源是根據控件樹一級一級往上找的,如果沒找到就會報錯。
在後台代碼中指定DataContex
profile_SP.DataContext = 我的姑娘;
也可以指定為這個頁面的DataContext
this.DataContext = 我的姑娘;
但這樣有個問題呀。假如你心儀這個姑娘很久了,你就一直盯著她的資料看,但是,姑娘長膘了,從原來的100長到了150,但你不知道啊,因為你看到的是她原來的資料。這時候就需要實現INotifyPropertyChanged接口來通知前端後台發生了數據更改。
public class DispatcherManager
{
private CoreDispatcher _dispatcher;
public CoreDispatcher Dispatcher
{
get
{
return _dispatcher;
}
set
{
_dispatcher = value;
}
}
private static DispatcherManager _current;
public static DispatcherManager Current
{
get
{
if (_current == null)
{
_current = new DispatcherManager();
}
return _current;
}
}
}
public class 姑娘 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected async void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
if (PropertyChanged != null)
{
if (DispatcherManager.Current.Dispatcher == null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
else
{
if (DispatcherManager.Current.Dispatcher.HasThreadAccess)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
else
{
await DispatcherManager.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
delegate ()
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
});
}
}
}
}
public enum 臉蛋類型
{
光滑 = 0,
麻子 = 1
}
private double _weight;
private bool _islike;
public string 姓名 { get; set; }
public double 身高 { get; set; }
public double 體重
{
get { return _weight; }
set { _weight = value;OnPropertyChanged(); }
}
public 臉蛋類型 臉蛋 { get; set; }
public bool IsLike
{
get { return _islike; }
set { _islike = value;OnPropertyChanged(); }
}
}
好了現在姑娘長膘了我們可以隨時知道,也可以隨時”變心“了(都是“善變”的動物)。
先來看View:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<TextBlock Text="{Binding 姓名}"/>
<TextBlock Text="{Binding 身高}"/>
<TextBlock Text="{Binding 體重,Mode=TowWay}"/>
<TextBlock Text="{Binding 臉蛋}"/>
</StackPanel>
</Grid>
很簡單,就展示了姑娘的基本信息。
接下來設置ViewModel:
public delegate void MovieWatchEventHander();
public delegate void 頭腦發熱EventHandler();
public event MovieWatchEventHander MovieWatched;//看完一部愛情電影後
public event 頭腦發熱EventHandler 頭腦發熱ed;
private GrilViewModel _viewModel;
public GirlPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if(e.NavigationMode== NavigationMode.New)
{
this.DataContext = _viewModel = new GrilViewModel();
MovieWatched += GirlPage_MovieWatched;
頭腦發熱ed += GirlPage_頭腦發熱ed;
}
}
private async void GirlPage_頭腦發熱ed()
{
await _viewModel.表達愛慕();
}
private async void GirlPage_MovieWatched()
{
await _viewModel.表達愛慕();
}
注意這裡我為什麼不把事件等東西全部放到ViewModel呢?嚴格按照MVVM來說是的,應該放在ViewModel裡,但是,我們不要為了模式而模式,尤其是頁面的事件,Button的Click還好說,有Command,但是其他時間要寫到MVVM裡面就非常麻煩,而這並沒有給我們帶來明顯的好處,所以還是直接放到頁面的cs文件中比較好。
說說我理解的模式吧,就好比一個劍客
第一層:手中無劍,拿一根木棍胡亂打一通;就跟我們開始寫代碼,不管三七二十一,實現再說;
第二層:手中有劍,會一招一式,此時可以行走江湖,一般來說應付得過來;按照“模式”來;
第三曾:手中無劍,心中有劍,此時就是絕頂高手,殺人於無形;模式變通,無招勝有招;
哈哈,以上就是我瞎jb吹nb的,其實我就是個剛入門的菜鳥。希望各位大俠輕噴!