源碼地址:https://github.com/l2999019/DemoAppgit
能夠Star一下,隨意 - -github
嗯..前面3篇就是基礎內容..後面就開始逐漸要加深了,進階篇開始了.ide
今天咱們講講Xamarin中的MVVM雙向綁定,嗯..須要有必定的MVVM基礎.,具體什麼是MVVM - -,請百度,我就很少講了函數
效果以下:post
這個時間的功能很簡單,就是一個時間的動態顯示.學習
咱們首先建立一個基礎的頁面以下:this
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:DemoApp.MVVMDemo.ViewModel" x:Class="DemoApp.MVVMDemo.MVVMPageDemo"> <ContentPage.Content> <StackLayout > <Label Text="{Binding DateTime,StringFormat='{0:F}'}"> <Label.BindingContext> <local:TimeViewModel></local:TimeViewModel> </Label.BindingContext> </Label> </StackLayout> </ContentPage.Content> </ContentPage>
你們能夠發現,咱們此次多了一些內容.spa
首先,咱們會發現ContentPage的xmlns定義中多了一個local的定義.這個很重要,他是用來讓咱們在xaml中引用其餘程序集中的類,相似於Using的做用.雙向綁定
剩下的BindingContext和Bingding關鍵字,後面咱們慢慢講
接下來,咱們建立一個ViewModel的類以下:
public class TimeViewModel : INotifyPropertyChanged { //定義一個時間類型 DateTime dateTime; //實現接口的事件屬性 public event PropertyChangedEventHandler PropertyChanged; //建立構造函數,定義一個定時執行程序 public TimeViewModel() { this.DateTime = DateTime.Now; //定義定時執行程序,1秒刷新一下時間屬性 Device.StartTimer(TimeSpan.FromSeconds(1), () => { this.DateTime = DateTime.Now; return true; }); } //定義時間屬性,建立SetGet方法,在Set中使用PropertyChanged事件,來更新這個時間 public DateTime DateTime { set { if (dateTime != value) { dateTime = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("DateTime")); } } } get { return dateTime; } } }
咱們繼承了INotifyPropertyChanged,從類名就能夠看出來,這個是關於實現屬性變動事件的一個接口.
他包含一個PropertyChanged,屬性變動事件,咱們須要在每一個屬性變動的時候(也就是Set中),調用它
在具體的開發過程當中,若是你須要使用MVVM那麼你全部的ViewModel都應該繼承它.
不少解釋我都寫在了註釋裏面,請仔細看註釋
而後咱們回到Xaml中的BindingContext,它的做用就一目瞭然了,給這個Xaml控件,綁定一個上下文對象,也就是你定義的ViewModel,來方便你綁定其中的屬性
<Label Text="{Binding DateTime,StringFormat='{0:F}'}"> 這句的意思就是,綁定其中的DateTime屬性,並格式化顯示.
咱們在構造函數中啓動的定時程序,就會一直更新DateTime,對應的,頁面上也會一直隨着變動.這樣咱們就實現了一個基礎的MVVM
效果如圖:
經過上面的小栗子,咱們學習了一下基本的綁定關係和綁定方法.
那麼下面就來一個比較複雜,比較難的例子.效果是這樣的,如圖:
咱們建立三個數值,他們與控件Slider來綁定,並控制.更新值的同時,求和.獲得NumSun的值.
在界面中,咱們有一個清空的Button來清除這個ViewModel中的值.
首先,咱們建立xaml代碼以下:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:DemoApp.MVVMDemo.ViewModel" x:Class="DemoApp.MVVMDemo.MVVMDemoPage2"> <ContentPage.BindingContext> <local:AddNumViewModel></local:AddNumViewModel> </ContentPage.BindingContext> <ContentPage.Content> <StackLayout> <Label Text="{Binding NumSun,Mode=TwoWay,StringFormat='總數NumSun={0:F2}'}" /> <Label Text="{Binding Num1, StringFormat='Num1 = {0:F2}'}" /> <Slider Value="{Binding Num1,Mode=TwoWay}" /> <Label Text="{Binding Num2, StringFormat='Num2 = {0:F2}'}" /> <Slider Value="{Binding Num2,Mode=TwoWay}" /> <Label Text="{Binding Num3, StringFormat='Num3 = {0:F2}'}" /> <Slider Value="{Binding Num3,Mode=TwoWay}" /> <Button Text="清空" Command="{Binding CleanCommand}" /> </StackLayout> </ContentPage.Content> </ContentPage>
而後建立咱們的ViewModel代碼以下:
public class AddNumViewModel : INotifyPropertyChanged { //定義屬性值 double num1, num2, num3,numSun; public event PropertyChangedEventHandler PropertyChanged; //定義清空的命令 public ICommand CleanCommand { protected set; get; } public AddNumViewModel() { //實現清空 this.CleanCommand = new Command((key) => { this.NumSun = 0; this.Num1 = 0; this.Num2 = 0; this.Num3 = 0; }); } /// <summary> /// 統一的屬性變動事件判斷方法 /// </summary> /// <param name="propertyName"></param> protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public double Num1 { set { if (num1 != value) { num1 = value; OnPropertyChanged("Num1"); SetNewSunNum(); } } get { return num1; } } public double Num2 { set { if (num2 != value) { num2 = value; OnPropertyChanged("Num2"); SetNewSunNum(); } } get { return num2; } } public double Num3 { set { if (num3 != value) { num3 = value; OnPropertyChanged("Num3"); SetNewSunNum(); } } get { return num3; } } public double NumSun { set { if (numSun != value) { numSun = value; OnPropertyChanged("NumSun"); } } get { return numSun; } } /// <summary> /// 把數值加起來的方法(業務邏輯) /// </summary> void SetNewSunNum() { this.NumSun = this.Num1 + this.Num2 + this.Num3; } }
很簡單,咱們建立了Num1,Num2,Num3和NumSun四個屬性.實現了一個SetNewSunNum的方法,來求和.
而後就一一對應的在xaml中綁定了相關的屬性.全部的Slider綁定中都有個Mode=TwoWay,意思就是,這個屬性爲雙向綁定,在控件中變動它的同時,也會在ViewModel中變動.
而後咱們在來看看清空按鈕的命令綁定.
先解釋一下,爲何會有命令綁定這個東西,由於咱們使用雙向綁定的時候,頁面的點擊事件,並不能直接調用到ViewModel,因此就衍生了一個叫命令綁定的東西.來和咱們控件的各類事件相關聯.
咱們回到代碼,會發現,在AddNumViewModel中,咱們定義了一個繼承自 ICommand的CleanCommand 的命令,並在構造函數中實現了它
在咱們的xaml中,buttom綁定了這個事件 <Button Text="清空" Command="{Binding CleanCommand}" />
這樣,就能夠直接調用到ViewModel了,固然你的命令也能夠傳遞參數,以下:
<Button Text="清空" Command="{Binding CleanCommand}" CommandParameter="aaa" />
aaa就是你傳遞的參數.
接收也很簡單,稍微改一下.CleanCommand 以下:
這個key就是你傳遞進來的參數了..
今天主要學習了Xamarin中的MVVM雙向綁定和命令綁定,
須要雙向綁定的類,須要繼承INotifyPropertyChanged,須要綁定的命令,須要繼承:ICommand
最後,列一下可使用命令綁定的控件.
Button
MenuItem
ToolbarItem
SearchBar
TextCell(因此也包含
ImageCell
)
ListView
TapGestureRecognizer
除了SearchBar和
ListView這兩個控件
以外,這些控件均可以使用Command
和CommandParameter
嗯..,SearchBar
定義SearchCommand
和SearchCommandParameter
屬性,而ListView
定義一個RefreshCommand
屬性的類型ICommand
。
其實都是同樣的..名字換了一下..
嗯..沒啥好說的..持續更新中..