0x01 前言

就目前而言,MVVM可以说是挺流行的,无论是web端还是移动端,web端的主要代表angularjs,avalonjs等,

移动端(xamarin,uwp)的代表应该是mvvmlight,mvvmcross等,

我们的主题是移动端,所以主要讲mvvmlight,mvvmcross,这篇主要讲MvvmLight,下篇讲MvvmCross。

还是以Demo的形式来谈使用。

0x02 简单的MVVM(mvvmlight) Demo

先来个web版最简单的MVVM效果,然后在按xamarin.android->uwp的顺序做一样效果的demo

注:这个效果是基于 avalonjs的

下面来看看我们的第一个例子(Xamarin.Android):

新建一个Android项目Catcher.MVVMDemo.Day01DroidByMvvmLight

通过NuGet安装相关组件(MvvmLight)。

然后编写我们的Main.axml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent">
  6. <EditText
  7. android:layout_width="fill_parent"
  8. android:layout_height="wrap_content"
  9. android:id="@+id/et_input" />
  10. <TextView
  11. android:layout_width="fill_parent"
  12. android:layout_height="wrap_content"
  13. android:id="@+id/tv_input" />
  14. </LinearLayout>

然后去修改MainActivity

  1. using Android.App;
  2. using Android.OS;
  3. using Android.Widget;
  4. using GalaSoft.MvvmLight.Helpers;
  5. using GalaSoft.MvvmLight.Views;
  6. namespace Catcher.MVVMDemo.Day01DroidByMvvmLight
  7. {
  8. [Activity(Label = "MvvmLightDemo", MainLauncher = true, Icon = "@drawable/icon")]
  9. public class MainActivity : ActivityBase
  10. {
  11. EditText etInput;
  12. TextView tvInput;
  13. protected override void OnCreate(Bundle bundle)
  14. {
  15. base.OnCreate(bundle);
  16. SetContentView(Resource.Layout.Main);
  17. etInput = FindViewById<EditText>(Resource.Id.et_input);
  18. tvInput = FindViewById<TextView>(Resource.Id.tv_input);
  19.  
  20. this.SetBinding(() => etInput.Text, () => tvInput.Text);
  21. }
  22. }
  23. }

MainActivity是继承ActivityBase,同时将输入的值绑定在TextView上。

效果图如下:

第二个例子(UWP):

新建一个Universal Windows项目:Catcher.MVVMDemo.Day01UWP

修改我们的MainPage.xaml

  1. <Page
  2. x:Class="Catcher.MVVMDemo.Day01UWP.MainPage"
  3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:local="using:Catcher.MVVMDemo.Day01UWP"
  6. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  8. mc:Ignorable="d">
  9.  
  10. <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  11. <StackPanel VerticalAlignment="Top">
  12. <TextBox x:Name="txtName"/>
  13. <TextBlock Text="{Binding ElementName=txtName,Path=Text}"/>
  14. </StackPanel>
  15. </Grid>
  16. </Page>

这里直接在页面通过Binding来绑定了。相比Android简洁了不少。

效果如下:

到这里,这两个简单的例子已经OK了,你是不是也想动手试试呢!

不过这两个例子并没有涉及到Mvvm主要的东西。至少连ViewModel的影子都还没出现呢。

0x03 MVVM(mvvmlight) 登陆Demo

开始之前,我们新建一个类库项目Catcher.MVVMDemo.Day01Core

这个类库是后面的2个例子都要用到的,处理我们的ViewModel。

通过NuGet安装MvvmLight

在ViewModel文件夹下面添加一个LoginViewModel

  1. using GalaSoft.MvvmLight;
  2. using GalaSoft.MvvmLight.Command;
  3. using GalaSoft.MvvmLight.Messaging;
  4. using GalaSoft.MvvmLight.Views;
  5. using Microsoft.Practices.ServiceLocation;
  6. using System.Diagnostics;
  7. namespace Catcher.MVVMDemo.Day01Core.ViewModel
  8. {
  9. public class LoginViewModel : ViewModelBase
  10. {
  11. public LoginViewModel()
  12. {
  13. }
  14. private string _name;
  15. public string Name
  16. {
  17. get
  18. {
  19. return _name;
  20. }
  21. set
  22. {
  23. _name = value;
  24. //RaisePropertyChanged("Name");
  25. RaisePropertyChanged(() => Name);
  26. }
  27. }
  28. private string _password;
  29. public string Password
  30. {
  31. get
  32. {
  33. return _password;
  34. }
  35. set
  36. {
  37. _password = value;
  38. RaisePropertyChanged(() => Password);
  39. }
  40. }
  41. /// <summary>
  42. /// login command
  43. /// </summary>
  44. public RelayCommand LoginCommand
  45. {
  46. get
  47. {
  48. return new RelayCommand(() => Login());
  49. }
  50. }
  51. /// <summary>
  52. /// login
  53. /// </summary>
  54. private void Login()
  55. {
  56. //Valid the user
  57. if (Name == "catcher" && Password == "")
  58. {
  59. var nav = ServiceLocator.Current.GetInstance<INavigationService>();
  60. nav.NavigateTo("Main");
  61. }
  62. else
  63. {
  64. var dialog = ServiceLocator.Current.GetInstance<IDialogService>();
  65. dialog.ShowMessage(
  66. "check your name and password",
  67. "infomation",
  68. "OK",
  69. null);
  70. }
  71. }
  72. }
  73. }

这里的登陆是写死了一个用户名和密码。

同时,修改我们的ViewModelLocator,添加我们LoginViewModel的信息

  1. using GalaSoft.MvvmLight.Ioc;
  2. using Microsoft.Practices.ServiceLocation;
  3. namespace Catcher.MVVMDemo.Day01Core.ViewModel
  4. {
  5. public class ViewModelLocator
  6. {
  7. public ViewModelLocator()
  8. {
  9. //provider
  10. ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  11. //view model
  12. SimpleIoc.Default.Register<MainViewModel>();
  13. SimpleIoc.Default.Register<LoginViewModel>();
  14. }
  15. public MainViewModel Main
  16. {
  17. get
  18. {
  19. return ServiceLocator.Current.GetInstance<MainViewModel>();
  20. }
  21. }
  22. public LoginViewModel LoginViewModel
  23. {
  24. get
  25. {
  26. return ServiceLocator.Current.GetInstance<LoginViewModel>();
  27. }
  28. }
  29. public static void Cleanup()
  30. {
  31. }
  32. }
  33. }

到这里,我们将ViewModel的相关处理做好了。

下面两个例子就是添加一个登陆页面,提供验证,登陆成功就跳转到我们前面两个例子的页面,不成功就弹框提示。

第三个例子(Xamarin.Android):

在刚才的Catcher.MVVMDemo.Day01DroidByMvvmLight中,添加一个App.cs,主要是注册一些东西

  1. using Catcher.MVVMDemo.Day01Core.ViewModel;
  2. using GalaSoft.MvvmLight.Views;
  3. using GalaSoft.MvvmLight.Ioc;
  4. namespace Catcher.MVVMDemo.Day01DroidByMvvmLight
  5. {
  6. public static class App
  7. {
  8. private static ViewModelLocator _locator;
  9. public static ViewModelLocator Locator
  10. {
  11. get
  12. {
  13. if (_locator == null)
  14. {
  15. var nav = new NavigationService();
  16. nav.Configure("Main", typeof(MainActivity));
  17.  
  18. SimpleIoc.Default.Register<INavigationService>(() => nav);
  19. //the dialog
  20. SimpleIoc.Default.Register<IDialogService, DialogService>();
  21. _locator = new ViewModelLocator();
  22. }
  23. return _locator;
  24. }
  25. }
  26. }
  27. }

添加一个login.axml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent">
  6. <EditText
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content"
  9. android:hint="enter your name"
  10. android:id="@+id/et_name" />
  11. <EditText
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"
  14. android:inputType="textPassword"
  15. android:hint="enter your password"
  16. android:id="@+id/et_pwd" />
  17. <Button
  18. android:layout_width="match_parent"
  19. android:layout_height="wrap_content"
  20. android:text="Login"
  21. android:id="@+id/btn_login" />
  22. </LinearLayout>

添加一个LoginActivity,与LoginViewModel相适配。

  1. using Android.App;
  2. using Android.OS;
  3. using Android.Widget;
  4. using Catcher.MVVMDemo.Day01Core.ViewModel;
  5. using GalaSoft.MvvmLight.Helpers;
  6. using GalaSoft.MvvmLight.Views;
  7. namespace Catcher.MVVMDemo.Day01DroidByMvvmLight
  8. {
  9. [Activity(Label = "Login", MainLauncher = true, Icon = "@drawable/icon")]
  10. public class LoginActivity : ActivityBase
  11. {
  12. /// <summary>
  13. /// the view model
  14. /// </summary>
  15. public LoginViewModel VM
  16. {
  17. get { return App.Locator.LoginViewModel; }
  18. }
  19. protected override void OnCreate(Bundle savedInstanceState)
  20. {
  21. base.OnCreate(savedInstanceState);
  22. SetContentView(Resource.Layout.login);
  23. EditText etName = FindViewById<EditText>(Resource.Id.et_name);
  24. EditText etPassword = FindViewById<EditText>(Resource.Id.et_pwd);
  25. Button btnLogin = FindViewById<Button>(Resource.Id.btn_login);
  26. //binding
  27. this.SetBinding(() => VM.Name, etName, () => etName.Text, BindingMode.TwoWay);
  28. this.SetBinding(() => VM.Password, etPassword, () => etPassword.Text, BindingMode.TwoWay);
  29. //button click
  30. btnLogin.SetCommand("Click", VM.LoginCommand);
  31. }
  32. }
  33. }

VM通过App.cs里面的来获取。

两个输入框的绑定方式设为TwoWay。

按钮的点击事件设为LoginViewModel的LoginCommand。

最后去掉MainActivity的MainLauncher=true

效果图如下:

第四个例子(UWP):

在刚才的Catcher.MVVMDemo.Day01UWP中,添加一个LoginPage.xaml

  1. <Page
  2. x:Class="Catcher.MVVMDemo.Day01UWP.LoginPage"
  3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:local="using:Catcher.MVVMDemo.Day01UWP"
  6. xmlns:vm="using:Catcher.MVVMDemo.Day01Core.ViewModel"
  7. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  8. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  9. mc:Ignorable="d">
  10. <Page.DataContext>
  11. <vm:LoginViewModel />
  12. </Page.DataContext>
  13. <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  14. <Grid.RowDefinitions>
  15. <RowDefinition Height="*"></RowDefinition>
  16. <RowDefinition Height="*"></RowDefinition>
  17. <RowDefinition Height="*"></RowDefinition>
  18. <RowDefinition Height="*"></RowDefinition>
  19. <RowDefinition Height="5*"></RowDefinition>
  20. </Grid.RowDefinitions>
  21. <TextBox Grid.Row="1" Margin="15" Height="20" Text="{Binding Name,Mode=TwoWay}" PlaceholderText="enter you name" />
  22. <PasswordBox Grid.Row="2" Margin="15" Height="20" Password="{Binding Password,Mode=TwoWay}" PasswordChar="*" PlaceholderText="enter your password" />
  23. <Button Grid.Row="3" Margin="15,10" Content="Login" Command="{Binding LoginCommand}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
  24. </Grid>
  25. </Page>

通过Page.DataContext设置了ViewModel

对TextBox,PasswordBox和button进行了相应的绑定。

然后修改App.xaml.cs中的OnLaunched方法,主要是启动页面和注册MvvmLight的东西

  1. protected override void OnLaunched(LaunchActivatedEventArgs e)
  2. {
  3. #if DEBUG
  4. if (System.Diagnostics.Debugger.IsAttached)
  5. {
  6. this.DebugSettings.EnableFrameRateCounter = true;
  7. }
  8. #endif
  9. Frame rootFrame = Window.Current.Content as Frame;
  10. if (rootFrame == null)
  11. {
  12. rootFrame = new Frame();
  13. rootFrame.NavigationFailed += OnNavigationFailed;
  14. if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
  15. {
  16. }
  17.  
  18. Window.Current.Content = rootFrame;
  19. }
  20. if (e.PrelaunchActivated == false)
  21. {
  22. if (rootFrame.Content == null)
  23. {
  24. rootFrame.Navigate(typeof(LoginPage), e.Arguments);
  25. }
  26.  
  27. Window.Current.Activate();
  28. //
  29. ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  30. var navigationService = new NavigationService();
  31. navigationService.Configure("Login", typeof(LoginPage));
  32. navigationService.Configure("Main", typeof(MainPage));
  33. SimpleIoc.Default.Register<INavigationService>(() => navigationService);
  34. SimpleIoc.Default.Register<IDialogService, DialogService>();
  35. }
  36. }

效果图:

0x04 简单总结

对于Android来说,主要以下几个点:

1.Activity是继承了MvvmLight自己实现的ActivityBase,具体如下:

  1. namespace GalaSoft.MvvmLight.Views
  2. {
  3. public class ActivityBase : Activity
  4. {
  5. public ActivityBase();
  6. public static ActivityBase CurrentActivity { get; }
  7. public static void GoBack();
  8. protected override void OnResume();
  9. }
  10. }

2.ViewModel继承ViewModelBase这个抽象类,在深究必然离不开INotifyPropertyChanged这个接口。

  1. public abstract class ViewModelBase : ObservableObject, ICleanup
  2.  
  3. public class ObservableObject : INotifyPropertyChanged

3.在ViewModelLocator里面通过SimpleIoc注册我们的ViewModel,当然也可以用Autofac等。

4.SetBinding和SetCommand的应用,可以看看具体的实现

对UWP来说,除了公共部分,与Android的区别就是在xaml中绑定了属性和“事件”。

下一篇会讲讲MvvmCross的简单使用。

Xamarin.Android和UWP之MVVM的简单使用(一)的更多相关文章

  1. Xamarin.Android和UWP之MVVM的简单使用(二)

    0x01 前言 前面一篇,Xamarin.Android和UWP之MVVM的简单使用(一),主要讲了MvvmLight的简单使用 这篇主要讲讲MvvmCross的简单使用,例子的话,还是和上篇的一样. ...

  2. Xamarin.Android之Splash的几种简单实现

    对现在的APP软件来说,基本上都会有一个Splash页面,类似大家常说的欢迎页面.启动界面之类的. 正常来说这个页面都会有一些相关的信息,比如一些理念,Logo,版本信息等 下面就来看看在Xamari ...

  3. Xamarin android spinner的使用方法

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  4. Xamarin Android 中Acitvity如何传递数据

    在xamarin android的开发中,activity传递数据非常常见,下面我也来记一下在android中activity之间传递数据的几种方式, Xamarin Android中Activity ...

  5. MVP架构在xamarin android中的简单使用

    好几个月没写文章了,使用xamarin android也快接近两年,还有一个月职业生涯就到两个年了,从刚出来啥也不会了,到现在回头看这个项目,真jb操蛋(真辛苦了实施的人了,无数次吐槽怎么这么丑),怪 ...

  6. Xamarin.Android之引导页的简单制作

    0x01 前言 对于现在大部分的APP,第一次打开刚安装或更新安装的APP都会有几个引导界面,通常这几个引导页是告诉用户 APP有些什么功能或者修改了什么bug.新增了什么功能等等等. 下面就用Xam ...

  7. Xamarin.Android之简单的抽屉布局

    0x01 前言 相信对于用过Android版QQ的,应该都不会陌生它那个向右滑动的菜单(虽说我用的是Lumia) 今天就用Xamarin.Android实现个比较简单的抽屉布局.下面直接进正题. 0x ...

  8. Xamarin.Android之封装个简单的网络请求类

    一.前言 回忆到上篇 <Xamarin.Android再体验之简单的登录Demo> 做登录时,用的是GET的请求,还用的是同步, 于是现在将其简单的改写,做了个简单的封装,包含基于Http ...

  9. 基于Xamarin Android实现的简单的浏览器

    最近做了一个Android浏览器,当然功能比较简单,主要实现了自己想要的一些功能……现在有好多浏览器为什么还要自己写?当你使用的时候总有那么一些地方不如意,于是就想自己写一个. 开发环境:Xamari ...

随机推荐

  1. 数据库中的two phase locking

    数据库中的two phase locking 两段锁协议是指每个事务的执行可以分为两个阶段:生长阶段(加锁阶段)和衰退阶段(解锁阶段). 加锁阶段:在该阶段可以进行加锁操作.在对任何数据进行读操作之前 ...

  2. 浅析用Base64编码的图片优化网页加载速度

    想必大家都知道网页加载的过程,从开始请求,到加载页面,开始解析和显示网页,遇到图片就再次向服务器发送请求,加载图片.如果图片很多的话,就会产生大量的http请求,从而影响页面的加载速度.所以现在有一种 ...

  3. 【Java并发编程实战】-----“J.U.C”:Semaphore

    信号量Semaphore是一个控制访问多个共享资源的计数器,它本质上是一个"共享锁". Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的ReentrantLock就是 ...

  4. Android 两个activity生命周期的关系

    Acitivity的生命周期想必大家都清楚,但是两个activity之间其实不是独立各自进行的. 从第一个activity1启动另外一个activity2时,会先调用本activity1的onPaus ...

  5. Thread.Sleep引发ThreadAbortException异常

    短信平台记录日志模块,是通过异步方式来记录的,即日志工具类里初始化一个Queue对象,公共的写日志方法的处理逻辑是把日志消息放到Queue里.构造器里设定一个死循环,不停的读队,然后把日志消息持久化到 ...

  6. PowerDesigner成功生成PDM进行check model后的错误提示解决途径

    1.existence of reference join------->缺少主键; 2.constraint name uniquesness-------->关联约束重名(refere ...

  7. ClickOnce部署

    (1):一些发布方式 ClickOnce是什么玩意儿,这个问题嘛,在21世纪的互联网严重发达的时代,估计也没有必要大费奏章去介绍了,弄不好的话,还有抄袭之嫌.因此,有关ClickOnce的介绍,各位朋 ...

  8. bootstrap中的Grid system详解

    啦啦啦,都十月中旬啦,好快啊,这个月的多一半都过去了,然而我才写第三篇随笔,小颖得加油啦~~~ 下面来看下小颖给大家分享的内容 1.   .col-md-*和.col-xs-* <!doctyp ...

  9. 学用MVC4做网站六后台管理:6.1管理员(续)

    接6.1 首先在~/Areas/Admin/Models文件夹添加管理员模型Administrator.cs using System.ComponentModel.DataAnnotations; ...

  10. 取消vs2013在solution中单击打开文件的功能

    2013用了一段时间,不错,就是单击会打开文件,有点恼人(因人而异吧).解决方案: 取消红色框框里面的那个checkbox就ok了. 来自为知笔记(Wiz)