mvvm_mvvm wpf - CSDN
mvvm 订阅
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。微软的WPF带来了新的技术体验,如Silverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。 展开全文
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。微软的WPF带来了新的技术体验,如Silverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。
信息
例    如
Silverlight、音频
外文名
Model-View-ViewModel
简    称
MVVM
隶    属
微软
MVVM优点
低耦合 可重用性
MVVM实例解析
WPF的数据绑定与Presentation Model相结合是非常好的做法,使得开发人员可以将 View和逻辑分离出来,但这种数据绑定技术非常简单实用,也是WPF所特有的,所以我们又称之为Model-View-ViewModel(MVVM)。这种模式跟经典的MVP(Model-View-Presenter)模式很相似,除了你需要一个为View量身定制的model,这个model就是ViewModel。ViewModel包含所有由UI特定的接口和属性,并由一个 ViewModel 的视图的绑定属性,并可获得二者之间的松散耦合,所以需要在ViewModel 直接更新视图中编写相应代码。数据绑定系统还支持提供了标准化的方式传输到视图的验证错误的输入的验证。在视图(View)部分,通常也就是一个Aspx页面。在以前设计模式中由于没有清晰的职责划分,UI 层经常成为逻辑层的全能代理,而后者实际上属于应用程序的其他层。MVP 里的M 其实和MVC里的M是一个,都是封装了核心数据、逻辑和功能的计算关系的模型,而V是视图(窗体),P就是封装了窗体中的所有操作、响应用户的输入输出、事件等,与MVC里的C差不多,区别是MVC是系统级架构的,而MVP是用在某个特定页面上的,也就是说MVP的灵活性要远远大于MVC,实现起来也极为简单。我们再从IView这个interface层来解析,它可以帮助我们把各类UI与逻辑层解耦,同时可以从UI层进入自动化测试(Unit/Automatic Test)并提供了入口,在以前可以由WinForm/Web Form/MFC等编写的UI是通过事件Windows消息与IView层沟通的。WPF与IView层的沟通,最佳的手段是使用Binding,当然,也可以使用事件;Presenter层要实现IView,多态机制可以保证运行时UI层显示恰当的数据。比如Binding,在程序中,你可能看到Binding的Source是某个interface类型的变量,实际上,这个interface变量引用着的对象才是真正的数据源。MVC模式大家都已经非常熟悉了,在这里我就不赘述,这些模式也是依次进化而形成MVC—>MVP—>MVVM。有一句话说的好:当物体受到接力的时候,凡是有界面的地方就是最容易被撕下来的地方。因此,IView作为公共视图接口约束(契约)的一层意思;View则能传达解耦的一层意思。 [1] 
收起全文
精华内容
参与话题
  • mvvm个人理解

    千次阅读 2018-06-06 18:10:07
    做技术,,有什么好处么。。如果要我说的话,我之所以喜欢做技术,最大的原因是成就感吧。我喜欢做每当做完一个项目的时候的那份成就感...你有没有发现,这些框架跟jquery这些框架不一样,他们采用的都是mvvm的软件...

    做技术,,有什么好处么。。如果要我说的话,我之所以喜欢做技术,最大的原因是成就感吧。我喜欢做每当做完一个项目的时候的那份成就感。让我感觉自己的存在是有一定的价值的。但~也很累~终生学习是做技术的宿命吧。

    但是~话说回来了,哪行哪业不需要学习呢。对吧

    做前端就要不断的学习各种流行的框架,react,angular,vue。。你有没有发现,这些框架跟jquery这些框架不一样,他们采用的都是mvvm的软件架构设计模式。

    什么是mvvm呢

    简单来说,mvvm是modal-view-viewmodel的缩写。

    View层

    View层是视图层,也就是用户界面。

    Model层

    Model是指数据模型,也就是后端进行业务处理和数据处理

    ViewModel层

    ViewModel是由前端开发人员组织生成和维护的视图数据层。在这里,前端可以对从后端获取的model数据进行转换处理,以便于前端的View层使用。

    双向数据绑定和单项数据绑定对比

    <body>
    		<div class="container">
    			<p class="name">丽丽</p>
    			<p class="age">23</p>
    		</div>
    		<script type="text/javascript">
    			$(".name").html("花花");
    			$(".age").html("26")
    		</script>
    	</body>

    这时候,我们如果想改变name和age的值,就要进行dom操作,选中name和age元素,然后进行赋值操作。这是进行少量简单的改变视图操作,如果进行大量的视图绑定的数据改变的时候就会变得比较麻烦,这时候会凸显出mvvm的优势。

    下面我们用vue.js作出变化

    <div class="container">
    			<p class="name">{{user.name}}</p>
    			<p class="age">{{user.age}}</p>
    			<button @click="change">点击我</button>
    		</div>
    		<script type="text/javascript">
    				new Vue({
    					el:".container",
    					data:{
    						user:{"name":'丽丽',"age":'23'}
    					},
    					methods:{
    						change:function(){
    							this.user.name="花花";
    							this.user.age="24"
    						}
    					}
    					
    					
    				})
    		</script>

    这时候我们点击按钮只需要改变数据就能改变视图,让视图更新。所以我们前端开发者只需要关注ViewModel层,而不需要进行复杂的dom操作,真的是给我们前端开发者省去了很多很多的麻烦。

    <div class="container">
    			<input type="text" v-model="name" />
    			<p>{{name}}</p>
    		</div>
    		<script type="text/javascript">
    				new Vue({
    					el:".container",
    					data:{
    						name:"lili"
    					}
    				})
    		</script>

    双向数据绑定当我们输入框里的值改变数据也会随之改变,设想一下,如果我们提交表单时候是不是不需要在一个个的整理表单数据然后发送给后端,因为客户端输入的内容我们直接就得到了,而且是以对象的形式进行的存储,是不是可以直接发送给后端使用。是不是又给我们带来了极大的方便~~

    小伙伴们,mvvm架构设计模式是现在和以后前端流行的趋势。so~能不学么


    展开全文
  • MVVM

    千次阅读 2016-12-18 13:13:43
    目的:便于开发和维护代码M(Model):数据模型 V(View + Controller): 展示内容 + 如何展示 VM(ViewModel):视图模型,处理展示的业务逻辑,包括按钮的点击,数据的请求和解析登录功能实现MVC实现: ...

    目的:便于开发和维护代码

    M(Model):数据模型
    V(View + Controller): 展示内容 + 如何展示
    VM(ViewModel):视图模型,处理展示的业务逻辑,包括按钮的点击,数据的请求和解析

    登录功能实现

    MVC实现:
    这里写图片描述

    #import "ViewController.h"
    #import "ReactiveCocoa.h"
    #import <MBProgressHUD/MBProgressHUD.h>
    
    @interface ViewController ()
    
    @property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
    @property (weak, nonatomic) IBOutlet UITextField *pawwordTextField;
    @property (weak, nonatomic) IBOutlet UIButton *loginButton;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    
        // 字段校验(当用户名和密码都不为空的时候,登录按钮才可以点击)-----------------------------------
        RACSignal *validateFieldSignal = [RACSignal combineLatest:@[_usernameTextField.rac_textSignal, _pawwordTextField.rac_textSignal] reduce:^id(NSString *username, NSString *password){
            return @(username.length && password.length);
        }];
    
        RAC(_loginButton, enabled) = validateFieldSignal;
    
        // 按钮点击事件------------------------------------------
        RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            NSLog(@"请求接口登录...");
    
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                NSLog(@"发送响应的登录数据");
                [subscriber sendNext:@"发送响应的登录数据"];
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [subscriber sendCompleted];
                });
    
                return nil;
            }];
        }];
    
        [command.executionSignals.switchToLatest subscribeNext:^(id x) {
            NSLog(@"接收登录的数据");
        }];
    
        // 监听命令的执行过程
        [[command.executing skip:1] subscribeNext:^(id x) {
            if ([x boolValue] == YES) {
                NSLog(@"正在登录ing...");
                [MBProgressHUD showHUDAddedTo:self.view animated:YES];
            } else {
                NSLog(@"登录完成!");
                [MBProgressHUD hideHUDForView:self.view animated:YES];
            }
        }];
    
        [[_loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
            NSLog(@"点击登录按钮");
            [command execute:nil];
        }];  
    }
    
    @end
    
    2016-12-18 11:08:32.704 ReactiveCocoa[47893:7242989] 点击登录按钮
    2016-12-18 11:09:10.111 ReactiveCocoa[47893:7242989] 请求接口登录...
    2016-12-18 11:09:13.871 ReactiveCocoa[47893:7242989] 正在登录ing...
    2016-12-18 11:11:58.765 ReactiveCocoa[47893:7242989] 发送响应的登录数据
    2016-12-18 11:12:02.722 ReactiveCocoa[47893:7242989] 接收登录的数据
    2016-12-18 11:12:07.418 ReactiveCocoa[47893:7242989] 登录完成!

    代码分析:
    1. 程序启动时就会执行聚合信号combineLatest:reduce:,结果是登录按钮不可点击
    2. 当执行到创建命令RACCommand时,参数代码块和内部代码块都不执行
    3. 当执行内部信号订阅时(command.executionSignals.switchToLatest),订阅的代码块也不执行
    4. 命令的执行过程也不会得到执行(因为命令还没开始执行)
    5. 按钮事件rac_signalForControlEvents:也不会执行(因为没有点击按钮)
    6. 当每输入用户名和密码时都会执行聚合信号,来判断按钮是否可以点击(每当UITextField的文本发生改变,内部就会产生一个信号)
    7. 单击登录按钮打印@”点击登录按钮”并执行命令([command execute:nil]),紧接着会执行初始化命令时传的代码块参数signalBlock, 也就打印NSLog(@”请求接口登录…”); 一但命令执行了,那么就会监听到命令的执行过程,接着订阅命令执行过程的代码块,打印NSLog(@”正在登录ing…”); 当signalBlock执行完时会返回一个信号RACSignal,也就是说会产生一个信号,那么从信号源中就能拿到返回的信号并订阅,(command.executionSignals.switchToLatest),一但订阅就会执行命令返回的信号中的代码块,接着打印NSLog(@”发送响应的登录数据”); ,当执行sendNext的时候会发送新号,接着打印NSLog(@”接收登录的数据”);, 当执行过sendCompleted时候就会打印NSLog(@”登录完成!”);


    VM:处理界面上的所有业务逻辑,每一个控制器对应一个VM,VM中最好不要包括UI

    MVVM实现:

    #import <Foundation/Foundation.h>
    #import "ReactiveCocoa.h"
    
    @interface LoginViewModel : NSObject
    
    @property (strong, nonatomic) NSString *username;
    @property (strong, nonatomic) NSString *password;
    
    
    @property (strong, nonatomic, readonly) RACSignal *validateFieldSignal;
    @property (strong, nonatomic, readonly) RACCommand *loginCommand;
    
    @end
    
    
    #import "LoginViewModel.h"
    #import <MBProgressHUD/MBProgressHUD.h>
    
    @implementation LoginViewModel
    - (instancetype)init {
        if (self = [super init]) {
            [self setup];
        }
    
        return self;
    }
    
    - (void)setup {
        _validateFieldSignal = [RACSignal combineLatest:@[RACObserve(self, username), RACObserve(self, password)] reduce:^id(NSString *username, NSString *password){
            return @(username.length && password.length);
        }];
    
        _loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            NSLog(@"请求接口登录...");
    
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                NSLog(@"发送响应的登录数据");
                [subscriber sendNext:@"发送响应的登录数据"];
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [subscriber sendCompleted];
                });
    
                return nil;
            }];
        }];
    
    
        [_loginCommand.executionSignals.switchToLatest subscribeNext:^(id x) {
            NSLog(@"接收登录的数据");
        }];
    
        // 监听命令的执行过程
        [[_loginCommand.executing skip:1] subscribeNext:^(id x) {
            UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
            if ([x boolValue] == YES) {
                NSLog(@"正在登录ing...");
    
                [MBProgressHUD showHUDAddedTo:keyWindow animated:YES];
            } else {
                NSLog(@"登录完成!");
                [MBProgressHUD hideHUDForView:keyWindow animated:YES];
            }
        }];
    }
    @end
    
    #import "ViewController.h"
    #import "LoginViewModel.h"
    
    #import "ReactiveCocoa.h"
    #import <MBProgressHUD/MBProgressHUD.h>
    
    @interface ViewController ()
    
    @property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
    @property (weak, nonatomic) IBOutlet UITextField *pawwordTextField;
    @property (weak, nonatomic) IBOutlet UIButton *loginButton;
    
    @property (strong, nonatomic) LoginViewModel *loginViewModel;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    
        // 绑定值
        RAC(self.loginViewModel, username) = _usernameTextField.rac_textSignal;
        RAC(self.loginViewModel, password) = _pawwordTextField.rac_textSignal;
        RAC(_loginButton, enabled) = self.loginViewModel.validateFieldSignal;
    
        // 处理事件
        [[_loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
            NSLog(@"点击登录按钮");
            [self.loginViewModel.loginCommand execute:nil];
        }];
    }
    
    - (LoginViewModel *)loginViewModel {
        if (_loginViewModel == nil) {
            _loginViewModel = [[LoginViewModel alloc] init];
        }
    
        return _loginViewModel;
    }
    
    @end

    RAC请求接口:


    #import "ViewController.h"
    #import "RequestViewModel.h"
    #import "ReactiveCocoa.h"
    
    @interface ViewController ()
    
    @property (strong, nonatomic) RequestViewModel *requestViewModel;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    
        RACSignal *signal = [self.requestViewModel.requestCommand execute:nil];
        [signal subscribeNext:^(id x) {
            NSLog(@"%@", x);
        }];
    
    }
    
    - (RequestViewModel *)requestViewModel {
        if (_requestViewModel == nil) {
            _requestViewModel = [[RequestViewModel alloc] init];
        }
    
        return _requestViewModel;
    }
    
    @end
    
    #import "ViewController.h"
    #import "RequestViewModel.h"
    
    #import "ReactiveCocoa.h"
    
    
    
    @interface ViewController ()
    
    @property (strong, nonatomic) RequestViewModel *requestViewModel;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    
        RACSignal *signal = [self.requestViewModel.requestCommand execute:nil];
        [signal subscribeNext:^(id x) {
            NSLog(@"%@", x);
        }];
    
    }
    
    - (RequestViewModel *)requestViewModel {
        if (_requestViewModel == nil) {
            _requestViewModel = [[RequestViewModel alloc] init];
        }
    
        return _requestViewModel;
    }
    
    @end
    #import <Foundation/Foundation.h>
    #import "ReactiveCocoa.h"
    
    @interface RequestViewModel : NSObject
    
    @property (strong, nonatomic) RACCommand *requestCommand;
    @end
    #import "RequestViewModel.h"
    #import <AFNetworking/AFNetworking.h>
    
    @implementation RequestViewModel
    
    - (RACCommand *)requestCommand {
        if (_requestCommand == nil) {
            _requestCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
                RACSignal *requstSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
                    NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
                    parameters[@"q"] = @"美女";
                    [manager GET:@"https://api.douban.com/v2/book/search 
    
    " parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    
                        [subscriber sendNext:responseObject[@"books"]];
    
                    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    
                    }];
    
                    return nil;
                }];
    
    
                return requstSignal;
            }];
        }
    
        return _requestCommand;
    }
    
    @end
    
    展开全文
  • MVVM是什么?以及MVVM优点

    千次阅读 2019-06-12 08:40:53
    MVVM 1、MVVM是什么? MVVM是Model-View-ViewModel的简写 它本质上是MVC 的改进版 MVVM(Model-View-ViewModel)框架的由来是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架...

    MVVM

    1、MVVM是什么?

    1. MVVM是Model-View-ViewModel的简写
    2. 它本质上是MVC 的改进版
    3. MVVM(Model-View-ViewModel)框架的由来是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架

    2、MVVM优点

    • MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点

    1. 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变

    2. 可重用性:你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑

    3. 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码

    4. 可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写

    展开全文
  • MVVM简介与运用

    万次阅读 2016-08-01 16:22:19
    在介绍MVVM框架之前,先给大家简单介绍一下MVC、MVP框架(由于本博文主要讲解MVVM,所以MVC和MVP将简化介绍,如果需要我将在以后的博文中补充进来)。 MVC框架: M-Model : 业务逻辑和实体模型(biz/bean) V-...

    前言

    在介绍MVVM框架之前,先给大家简单介绍一下MVC、MVP框架(由于本博文主要讲解MVVM,所以MVC和MVP将简化介绍,如果需要我将在以后的博文中补充进来)。

    MVC框架:

    • M-Model : 业务逻辑和实体模型(biz/bean)
    • V-View : 布局文件(XML)
    • C-Controller : 控制器(Activity)

    相信大家都熟悉这个框架,这个也是初学者最常用的框架,该框架虽然也是把代码逻辑和UI层分离,但是View层能做的事情还是很少的,很多对于页面的呈现还是交由C实现,这样会导致项目中C的代码臃肿,如果项目小,代码臃肿点还是能接受的,但是随着项目的不断迭代,代码量的增加,你就会没办法忍受该框架开发的项目,这时MVP框架就应运而生。

    MVP框架:

    • M-Model : 业务逻辑和实体模型(biz/bean)
    • V-View : 布局文件(XML)和Activity
    • P-Presenter : 完成View和Model的交互

    MVP框架相对于MVC框架做了较大的改变,将Activity当做View使用,代替MVC框架中的C的是P,对比MVC和MVP的模型图可以发现变化最大的是View层和Model层不在直接通信,所有交互的工作都交由Presenter层来解决。既然两者都通过Presenter来通信,为了复用和可拓展性,MVP框架基于接口设计的理念大家自然就可以理解其用意。

    但MVP框架也有不足之处:

    1.接口过多,一定程度影响了编码效率。

    2.业务逻辑抽象到Presenter中,较为复杂的界面Activity代码量依然会很多。

    3.导致Presenter的代码量过大。

     

    MVVM框架:

    • M-Model : 实体模型(biz/bean)
    • V-View : 布局文件(XML)
    • VM-ViewModel : DataBinding所在之处,对外暴露出公共属性,View和Model的绑定器

    对比MVP和MVVM模型图可以看出,他们之间区别主要体现在以下两点:


    1.    可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。 在Android中,布局里可以进行一个视图逻辑,并且Model发生变化,View也随着发生变化。


    2.    低耦合。以前Activity、Fragment中需要把数据填充到View,还要进行一些视图逻辑。现在这些都可在布局中完成(具体代码请看后面) 甚至都不需要再Activity、Fragment去findViewById()。这时候Activity、Fragment只需要做好的逻辑处理就可以了。


    说了这么多理论知识,相信大家都有所厌烦了,下面就不来“虚”的了直接来“干”的,大家可能会问MVVM框架在Android怎么样使用?

    Google在2015年的已经为我们提供DataBinding技术,以便让我们快速实现MVVM框架的实现。下面就详细讲解如何使用DataBinding?


    由于本人使用的是AndroidStudio(以下简称AS),所以接下来都是关于AS相关使用规则:

    1.检查你的AS版本,要求在1.3.0以上

    2.Gradle 版本1.3.0-beta4以上

    3.在工程根目录build.gradle文件加入如下配置:

    dependencies {
          classpath "com.android.tools.build:gradle:1.3.0-beta4"
          classpath "com.android.databinding:dataBinder:1.0-rc1"
       }

    allprojects {
       repositories {
           jcenter()
       }
    }

    4.在app里的build.gradle文件加入如下配置:

    apply plugin: 'com.android.application'
    apply plugin: 'com.android.databinding'


    下面来比较一下布局与之前大家常用的格式的区别:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"/>
       </LinearLayout>
    </layout>

    l  先将根布局改为layout

    l  在布局里引入的model 中的数据类:

    <variable name="user" type="com.example.User"/>(还有一种写法将在后面代码中介绍)

    l  设置布局属性值,通过@{}语法:

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@{user.firstName}"/>


    数据实体类User:

    public class User {
       private final String firstName;
       private final String lastName;
       public User(String firstName, String lastName) {
           this.firstName = firstName;
           this.lastName = lastName;
       }
       public String getFirstName() {
           return this.firstName;
       }
       public String getLastName() {
           return this.lastName;
       }
    }


    在Activity中进行数据的绑定:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
       User user = new User("Test", "User");
       binding.setUser(user);
    }


    这时你运行程序就会看到在界面上会显示你设置的测试用户数据,当然你还可以这样做去获取binding:

    MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

    如果你使用的是ListView或者RecyclerView去显示界面,这时候在Items布局中使用Data Binding,在Adapter中你可以这样获取binding:

    ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
    //or
    ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);


    接下来就是事件的实现,在我们以往的使用中对于事件的实现都是android:onClick或者在代码中使用View.setOnClickListener()来实现点击事件,在这里将有一种新的实现方式:

    要将事件分配给它的处理程序,使用一个正常的绑定表达式,以值作为调用的方法名称。例如:你的数据对象有两种方法

    public class MyHandlers {
        public void onClickFriend(View view) { ... }
        public void onClickEnemy(View view) { ... }
    }


    绑定表达式可以为视图指定单击事件监听器

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="handlers" type="com.example.Handlers"/>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"
               android:onClick="@{user.isFriend ?handlers.onClickFriend :handlers.onClickEnemy}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"
               android:onClick="@{user.isFriend ?handlers.onClickFriend :handlers.onClickEnemy}"/>
       </LinearLayout>
    </layout>


    由于DataBinding对布局使用改动比较大,下面主要讲解一下布局:


    ①在布局中import导入

    <data>
        <import type="android.view.View"/>
    </data>

     

    之后在你的布局中通过View控件特性进行对其实现类隐藏和显示操作

    <TextView
       android:text="@{user.lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

    可能有人会问如果我导入的类与已导入的类的名字冲突怎么办?那么接下来就会解决这个问题!

    <import type="android.view.View"/>
    <import type="com.example.real.estate.View"
            alias="Vista"/>

    这里的“alias”属性就是别名的意思,你可以采用别名的方式解决这个问题。


    ②当你在布局中引用的变量是一个List集合,需将集合的左”<”使用转义字符输入,如下(想要了解转义字符具体表达形式,请自行查询):

    <data>
        <import type="com.example.User"/>
        <import type="java.util.List"/>
        <variable name="user" type="User"/>
        <variable name="userList" type="List&lt;User>"/>
    </data>


    ③类型转换

    <TextView
       android:text="@{((User)(user.connection)).lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>


    ④当导入的类中存在静态属性和方法时,你也是可以在布局中直接使用

    <data>
        <import type="com.example.MyStringUtils"/>
        <variable name="user" type="com.example.User"/>
    </data><TextView
       android:text="@{MyStringUtils.capitalize(user.lastName)}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>


    ⑤属性Variables:

    在数据元素中可以使用任意数量的变量元素。每个可变元素描述一个属性,该属性可以设置在布局文件中的绑定表达式中使用的布局上:

    <data>
        <import type="android.graphics.drawable.Drawable"/>
        <variable name="user"  type="com.example.User"/>
        <variable name="image" type="Drawable"/>
        <variable name="note"  type="String"/>
    </data>


    ⑥自定义Binding类的类名:

    <data class="CustomBinding"></data> 在app_package/databinding下生成CustomBinding;

    <data class=".CustomBinding"></data> 在app_package下生成CustomBinding;

    <dataclass="com.example.CustomBinding"></data> 明确指定包名和类名。


    ⑦include使用

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:bind="http://schemas.android.com/apk/res-auto">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <include layout="@layout/name"
               bind:user="@{user}"/>
           <include layout="@layout/contact"
               bind:user="@{user}"/>
       </LinearLayout>
    </layout>


    ⑧DataBinding数据绑定不支持包括合并元素的直接子元素,例如下面的写法是不被允许的:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:bind="http://schemas.android.com/apk/res-auto">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <merge>
           <include layout="@layout/name"
               bind:user="@{user}"/>
           <include layout="@layout/contact"
               bind:user="@{user}"/>
       </merge>
    </layout>

    注意:name.xml 和 contact.xml都必须包含 <variable name="user" ../>

    DataBinding支持的表达式有:

    数学表达式: + - / *%

    字符串拼接 +

    逻辑表达式&& ||

    位操作符 & | ^

    一元操作符 + - ! ~

    位移操作符 >>>>> <<

    比较操作符 == >< >= <=

    instanceof

    分组操作符 ()

    字面量 -character, String, numeric, null

    强转、方法调用

    字段访问

    数组访问 []

    三元操作符 ?

    聚合判断(Null Coalescing Operator)语法 ‘??’

    例如:

    android:text="@{String.valueOf(index + 1)}"
    android:visibility="@{age &lt; 13 ? View.GONE : View.VISIBLE}"
    android:transitionName='@{"image_" + id}'

    android:text="@{user.displayName ?? user.lastName}"

    上面代码的意思是如果displayName为null,则显示lastName,否则显示displayName;

    android:text="@{user.displayName != null ? user.displayName : user.lastName}"


    集合Collections

    <data>
        <import type="android.util.SparseArray"/>
        <import type="java.util.Map"/>
        <import type="java.util.List"/>
        <variable name="list" type="List&lt;String>"/>
        <variable name="sparse" type="SparseArray&lt;String>"/>
        <variable name="map" type="Map&lt;String, String>"/>
        <variable name="index" type="int"/>
        <variable name="key" type="String"/>
    </data>
    …
    android:text="@{list[index]}"
    …
    android:text="@{sparse[index]}"
    …
    android:text="@{map[key]}"


    ①String literals(字符串常量)

    当使用单引号围绕属性值时,在表达式中使用双引号是很容易的:

    android:text='@{map["firstName"]}'


    ②也可以使用双引号来环绕属性值。当你这样做的时候,String literals要么用&quot;或反引号(`):

    android:text="@{map[`firstName`}"
    android:text="@{map[&quot;firstName&quot;]}"


    Resources资源:

    在DataBinding语法中,可以把resource作为其中的一部分:

    android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"

    除了支持dimen,还支持color、string、drawable、anim等。

    注意:对mipmap图片资源支持还是有问题,目前只支持drawable。


    一些资源要求需明确的类型赋值:

    Type

    Normal Reference

    Expression Reference

    String[]

    @array

    @stringArray

    int[]

    @array

    @intArray

    TypedArray

    @array

    @typedArray

    Animator

    @animator

    @animator

    StateListAnimator

    @animator

    @stateListAnimator

    Color   int

    @color

    @color

    ColorStateList

    @color

    @colorStateList

    到这里基本的属性使用方法介绍就结束了,下面大家应该对数据变化时,UI如何呈现很迷惑,好了,现在开始讲数据的变化如何让UI的更新?

    任何普通的java对象(POJO)可用于数据绑定,但修改一个POJO不会造成UI更新。数据绑定(DataBinding)的真正力量可以通过给你的数据对象在数据改变时通知你来使用。有三种不同的数据变化通知机制,Observable objectsobservable fields, and observable collections。

    下面来逐个讲解:

    Observable Objects

    一个实现可观察到的接口的类,将允许绑定到绑定一个单一的监听器绑定到一个绑定对象,以监听该对象上的所有属性的更改;观察到的接口有一个机制来添加和删除监听器,但通知是由开发人员来进行的。为使开发更容易,一个基类,baseobservable,是为了实现监听器注册机制。数据类实现者仍然是负责通知时的性能变化。这是通过分配一个绑定注释getter和setter进行通知:

    private static class User extends BaseObservable {
       private String firstName;
       private String lastName;
       @Bindable
       public String getFirstName() {
           return this.firstName;
       }
       @Bindable
       public String getLastName() {
           return this.lastName;
       }
       public void setFirstName(String firstName) {
           this.firstName = firstName;
           notifyPropertyChanged(BR.firstName);
       }
       public void setLastName(String lastName) {
           this.lastName = lastName;
           notifyPropertyChanged(BR.lastName);
       }
    }

    注意:BR类自动生成的

    好了,现在你就会发现当通过set方法改变数据后,UI就会自动更新!

     

    ObservableFields

    private static class User {
       public final ObservableField<String> firstName = new ObservableField<>();
       public final ObservableField<String> lastName = new ObservableField<>();
       public final ObservableInt age = new ObservableInt();
    }

    在代码中设置数据:

    user.firstName.set("Google");
    int age = user.age.get();


    Observable Collections

    ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
    user.put("firstName", "Google");
    user.put("lastName", "Inc.");
    user.put("age", 17);

    布局中使用:

    <data>
        <import type="android.databinding.ObservableMap"/>
        <variable name="user" type="ObservableMap&lt;String, Object>"/>
    </data><TextView
       android:text='@{user["lastName"]}'
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    <TextView
       android:text='@{String.valueOf(1 + (Integer)user["age"])}'
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>


    如果集合的key是Integer,可以使用ObservableArrayList代替ObservableArrayMap

    ObservableArrayList<Object> user = new ObservableArrayList<>();
    user.add("Google");
    user.add("Inc.");
    user.add(17);


    在布局中使用:

    <data>
        <import type="android.databinding.ObservableList"/>
        <import type="com.example.my.app.Fields"/>
        <variable name="user" type="ObservableList&lt;Object>"/>
    </data><TextView
       android:text='@{user[Fields.LAST_NAME]}'
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    <TextView
       android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>

    文章写到这里,DataBinding的一些基本用法已经介绍完毕,如果您想要了解更加详细、全面的内容,请自行去sdk的Doc文档中阅读或者关注我以后的博文。


    第一次写博客,两天的奋斗,希望大家多多指点,有可能不够全面,由于项目工期压缩,没那么多时间详细介绍,希望大家可以多交流!


    参考文献:


    官方文档:

    SDK/docs/tools/data-binding/guide.html

    CSDN博客:

    http://blog.csdn.net/qq_17250009/article/details/51161074

    http://blog.csdn.net/johnny901114/article/details/50706329

    展开全文
  • MVVM的实现原理

    万次阅读 2019-01-04 15:16:02
    1.MVVM是什么? 响应式,双向数据绑定,即MVVM。是指数据层(Model)-视图层(View)-数据视图(ViewModel)的响应式框架。它包括: 1.修改View层,Model对应数据发生变化。 2.Model数据变化,不需要查找DOM,直接...
  • Android MVVM 系列之 Databinding(三) 所有博文会不定期的更新一下的,文章有不妥欢迎大家提建议! 这篇文章主要讲 Databinding 中注解的使用,给大家整理个字典出来,Databinding 中公开的 Api 中有以下注解 @...
  • Android架构(三)MVVM

    2020-09-17 22:10:24
    MVVM
  • Android中使用mvvm(三)

    2020-05-15 15:07:53
    基于DataBinding与LiveData的MVVM 在MVP模式下,随着业务逻辑的不断增加,UI也会变得越来的多样化,UI改变多样化势必会造成View层的接口case变多,View的接口类就会变得异常庞大。MVVM的方式完美的解决了MVP模式的...
  • 第三部分:表达式语言 文章目录第三部分:表达式语言常用操作符缺失操作符Null coalescing operator(`??`)避免非空指针异常资源语句include:传递参数 常用操作符 DataBinding允许开发者在布局文件中使用表达式语言...
  • 第四部分:MVVM 前面的主要内容,基本只是介绍了MVVM的基础DataBinding的语法和使用。但这远远不够,下面才是本文的重头戏。Android 的关于代码的组织方式(你也可以称之为设计模式),从MVC 到MVP 再到MVVM,经历了...
  • MVC、MVP、MVVM,我到底该怎么选?

    万次阅读 多人点赞 2020-08-27 17:09:53
    本文由玉刚说写作平台提供写作赞助 原作者:AndroFarmer 版权声明:本文版权归微信...比如看了好多篇文章都搞不懂MVC到底是个啥本来想写个MVP写着写着就变成MVC了,到底Databing和MVVM之间有啥见不得人的关系...
  • MVVM模式之基础篇

    千次阅读 2020-07-14 21:07:14
    MVVM的定义 如上所示,MVVM是Mode-View-ViewMode模式: Model :负责数据实现和逻辑处理,类似MVP。 View : 对应于Activity和XML,负责View的绘制以及与用户交互,类似MVP。 ViewModel : 创建关联,将model...
  • 什么是MVVMMVVM和MVC的区别?

    千次阅读 2018-08-30 15:59:14
    1. Mvvm定义MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将...
  • MVVM框架实践IOS集锦

    千次阅读 2015-06-18 09:12:25
    应用 ReactiveCocoa实现 http://www.cocoachina.com/bbs/read.php?tid=220409 浅谈iOS中MVVM的架构设计与团队协作 http://www.cocoachina.com/ios/20150122/10987.html
  • 在VS中安装/使用 MVVMLight

    千次阅读 2014-07-14 10:38:43
    一般来说,我喜欢使用NuGet来获取这些东西,比如Newtonsoft.Json、netlog4、MVVMLight 之类的东西。至于NuGet的使用,以后再说吧。为了直接进入正题,我们这里直接使用VS中的“扩展和更新”来安装MVVMLight组件。我...
  • 本系列文章主要介绍wpf/silverlight下开源框架mvvmlight的使用,mvvmlight是基于mvvm的一个轻量级的框架,包含mvvm基本架构和一些扩展的功能。 如果你还没接触过MVVM,那么先推荐你阅读Josh Smith写的关于MVVM模式...
  • WPF——MVVM点击弹出窗口

    千次阅读 2017-09-20 16:04:58
    ViewModel里面建的委托 false隐藏界面true显示
  • DevExpress基础教程(一)MVVM框架

    千次阅读 2018-11-15 15:52:43
    敬请期待
  • Angular是MVC还是MVVM

    千次阅读 2017-07-25 11:58:55
    Angular是MVC还是MVVM
1 2 3 4 5 ... 20
收藏数 53,047
精华内容 21,218
关键字:

mvvm