zoukankan      html  css  js  c++  java
  • C#使用Xamarin开发可移植移动应用(4.进阶篇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中,我们定义了一个继承自 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

    其实都是一样的..名字换了一下..

     

     
    写在最后

    嗯..没啥好说的..持续更新中..

  • 相关阅读:
    年终总结 2016-08-28 22:04 422人阅读 评论(26) 收藏
    [mysql]MySQL Daemon failed to start 2016-08-14 21:27 1121人阅读 评论(18) 收藏
    solrr初步了解 2016-07-31 22:29 380人阅读 评论(4) 收藏
    基于spring-boot的测试桩设计--几种常见的controller
    利用Factory-boy和sqlalchemy来批量生成数据库表数据
    job中shell脚本异常(删除不存在容器),导致job被打断执行的问题 脚本优化方法
    利用Factory-boy来生成实例数据
    pytest相关资源收集
    pytest 用 @pytest.mark.usefixtures("fixtureName")装饰类,可以让执行每个case前,都执行一遍指定的fixture
    pytest fixture 利用 params参数实现用例集合
  • 原文地址:https://www.cnblogs.com/GuZhenYin/p/7381973.html
Copyright © 2011-2022 走看看