C#使用Xamarin开发可移植移动应用(4.进阶篇MVVM双向绑定和命令绑定)附源码

简介: 原文:C#使用Xamarin开发可移植移动应用(4.进阶篇MVVM双向绑定和命令绑定)附源码前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.
原文: 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

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

 

 

 

 

 

 

 

写在最后

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

目录
相关文章
|
10天前
|
前端开发 JavaScript 安全
C#一分钟浅谈:Blazor WebAssembly 开发
Blazor WebAssembly 是一个客户端框架,允许开发者使用C#和Razor语法构建Web应用。本文介绍了Blazor WebAssembly的基本概念、常见问题及解决方案,包括路由配置、数据绑定、异步操作、状态管理和性能优化等方面的内容,并分享了一些易错点及如何避免的方法。希望这些内容能帮助你在Blazor WebAssembly开发中少走弯路,提高开发效率。
84 51
|
8天前
|
开发框架 缓存 .NET
C# 一分钟浅谈:Blazor Server 端开发
Blazor Server 是基于 ASP.NET Core 的框架,允许使用 C# 和 Razor 语法构建交互式 Web 应用。本文介绍 Blazor Server 的基本概念、快速入门、常见问题及解决方案,帮助开发者快速上手。涵盖创建应用、基本组件、数据绑定、状态管理、跨组件通信、错误处理和性能优化等内容。
21 1
|
9天前
|
缓存 C# 开发者
C# 一分钟浅谈:Blazor Server 端开发
本文介绍了 Blazor Server,一种基于 .NET 的 Web 开发模型,允许使用 C# 和 Razor 语法构建交互式 Web 应用。文章从基础概念、创建应用、常见问题及解决方案、易错点及避免方法等方面详细讲解,帮助开发者快速上手并提高开发效率。
30 2
|
18天前
|
测试技术 Go C#
C#一分钟浅谈:ReSharper 插件增强开发效率
【10月更文挑战第25天】ReSharper 是 JetBrains 开发的一款 Visual Studio 插件,旨在提高 .NET 开发者的生产力。它通过代码分析、重构、导航等功能,帮助开发者避免常见错误,提升代码质量和开发效率。本文将通过具体代码案例,详细介绍 ReSharper 的常见功能及其应用。
35 1
|
24天前
|
C# Python
使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究
【10月更文挑战第30天】使用 `wxPython` 开发跨平台桌面应用时,可以通过创建辅助类来模拟 C# 扩展函数的功能。具体步骤包括:1. 创建辅助类 `WxWidgetHelpers`;2. 在该类中定义静态方法,如 `set_button_color`;3. 在应用中调用这些方法。这种方法提高了代码的可读性和可维护性,无需修改 `wxPython` 库即可为控件添加自定义功能。但需要注意显式调用方法和避免命名冲突。
|
1月前
|
JSON C# 开发者
C#语言新特性深度剖析:提升你的.NET开发效率
【10月更文挑战第15天】C#语言凭借其强大的功能和易用性深受开发者喜爱。随着.NET平台的演进,C#不断引入新特性,如C# 7.0的模式匹配和C# 8.0的异步流,显著提升了开发效率和代码可维护性。本文将深入探讨这些新特性,助力开发者在.NET开发中更高效地利用它们。
34 1
|
1月前
|
开发框架 NoSQL MongoDB
C#/.NET/.NET Core开发实战教程集合
C#/.NET/.NET Core开发实战教程集合
|
6月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
198 3
|
17天前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
30 3
|
1月前
|
安全 C# 数据安全/隐私保护
实现C#编程文件夹加锁保护
【10月更文挑战第16天】本文介绍了两种用 C# 实现文件夹保护的方法:一是通过设置文件系统权限,阻止普通用户访问;二是使用加密技术,对文件夹中的文件进行加密,防止未授权访问。提供了示例代码和使用方法,适用于不同安全需求的场景。
110 0