C#使用Xamarin開發可移植移動應用(4.進階篇MVVM雙向綁定和命令綁定)附源碼

前言

系列目錄

C#使用Xamarin開發可移植移動應用目錄html

源碼地址:https://github.com/l2999019/DemoAppgit

能夠Star一下,隨意 - -github

說點什麼..

嗯..前面3篇就是基礎內容..後面就開始逐漸要加深了,進階篇開始了.ide

 

今天的學習內容?

今天咱們講講Xamarin中的MVVM雙向綁定,嗯..須要有必定的MVVM基礎.,具體什麼是MVVM - -,請百度,我就很少講了函數

效果以下:post

 

 

正文

1.簡單的入門Demo

這個時間的功能很簡單,就是一個時間的動態顯示.學習

咱們首先建立一個基礎的頁面以下: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

效果如圖:

 

 

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中,咱們定義了一個繼承自 ICommandCleanCommand 的命令,並在構造函數中實現了它

在咱們的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定義SearchCommandSearchCommandParameter屬性,而ListView定義一個RefreshCommand屬性的類型ICommand

其實都是同樣的..名字換了一下..

 

 

 

 

 

 

 

寫在最後

嗯..沒啥好說的..持續更新中..

相關文章
相關標籤/搜索