C#使用Xamarin開發可移植移動應用(3.進階篇MVVM雙向綁定和命令綁定)附源碼
系列目錄
C#使用Xamarin開發可移植移動應用目錄
源碼地址:https://github.com/l2999019/DemoApp
可以Star一下,隨意 - -
說點什麽..
嗯..前面3篇就是基礎內容..後面就開始逐漸要加深了,進階篇開始了.
今天的學習內容?
今天我們講講Xamarin中的MVVM雙向綁定,嗯..需要有一定的MVVM基礎.,具體什麽是MVVM - -,請百度,我就不多講了
效果如下:
正文
1.簡單的入門Demo
這個時間的功能很簡單,就是一個時間的動態顯示.
我們首先創建一個基礎的頁面如下:
<?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>
大家可以發現,我們這次多了一些內容.
首先,我們會發現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
效果如圖:
2.學會與控件相聯系,並綁定命令事件
通過上面的小栗子,我們學習了一下基本的綁定關系和綁定方法.
那麽下面就來一個比較復雜,比較難的例子.效果是這樣的,如圖:
我們創建三個數值,他們與控件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就是你傳遞進來的參數了..
3.回顧一下.
今天主要學習了Xamarin中的MVVM雙向綁定和命令綁定,
需要雙向綁定的類,需要繼承INotifyPropertyChanged,需要綁定的命令,需要繼承:ICommand
最後,列一下可以使用命令綁定的控件.
-
Button
-
MenuItem
-
ToolbarItem
-
SearchBar
-
TextCell(所以也包含
ImageCell
) -
ListView
-
TapGestureRecognizer
除了SearchBar和
ListView這兩個控件
之外,這些控件都可以使用Command
和CommandParameter
嗯..,SearchBar
定義SearchCommand
和SearchCommandParameter
屬性,而ListView
定義一個RefreshCommand
屬性的類型ICommand
。
其實都是一樣的..名字換了一下..
寫在最後
嗯..沒啥好說的..持續更新中..
C#使用Xamarin開發可移植移動應用(3.進階篇MVVM雙向綁定和命令綁定)附源碼