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

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/et_input" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_input" />
</LinearLayout>

然后去修改MainActivity

 using Android.App;
using Android.OS;
using Android.Widget;
using GalaSoft.MvvmLight.Helpers;
using GalaSoft.MvvmLight.Views;
namespace Catcher.MVVMDemo.Day01DroidByMvvmLight
{
[Activity(Label = "MvvmLightDemo", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : ActivityBase
{
EditText etInput;
TextView tvInput;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
etInput = FindViewById<EditText>(Resource.Id.et_input);
tvInput = FindViewById<TextView>(Resource.Id.tv_input); this.SetBinding(() => etInput.Text, () => tvInput.Text);
}
}
}

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

效果图如下:

第二个例子(UWP):

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

修改我们的MainPage.xaml

 <Page
x:Class="Catcher.MVVMDemo.Day01UWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Catcher.MVVMDemo.Day01UWP"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel VerticalAlignment="Top">
<TextBox x:Name="txtName"/>
<TextBlock Text="{Binding ElementName=txtName,Path=Text}"/>
</StackPanel>
</Grid>
</Page>

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

效果如下:

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

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

0x03 MVVM(mvvmlight) 登陆Demo

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

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

通过NuGet安装MvvmLight

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

 using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Views;
using Microsoft.Practices.ServiceLocation;
using System.Diagnostics;
namespace Catcher.MVVMDemo.Day01Core.ViewModel
{
public class LoginViewModel : ViewModelBase
{
public LoginViewModel()
{
}
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
//RaisePropertyChanged("Name");
RaisePropertyChanged(() => Name);
}
}
private string _password;
public string Password
{
get
{
return _password;
}
set
{
_password = value;
RaisePropertyChanged(() => Password);
}
}
/// <summary>
/// login command
/// </summary>
public RelayCommand LoginCommand
{
get
{
return new RelayCommand(() => Login());
}
}
/// <summary>
/// login
/// </summary>
private void Login()
{
//Valid the user
if (Name == "catcher" && Password == "")
{
var nav = ServiceLocator.Current.GetInstance<INavigationService>();
nav.NavigateTo("Main");
}
else
{
var dialog = ServiceLocator.Current.GetInstance<IDialogService>();
dialog.ShowMessage(
"check your name and password",
"infomation",
"OK",
null);
}
}
}
}

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

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

 using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
namespace Catcher.MVVMDemo.Day01Core.ViewModel
{
public class ViewModelLocator
{
public ViewModelLocator()
{
//provider
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
//view model
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<LoginViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public LoginViewModel LoginViewModel
{
get
{
return ServiceLocator.Current.GetInstance<LoginViewModel>();
}
}
public static void Cleanup()
{
}
}
}

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

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

第三个例子(Xamarin.Android):

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

 using Catcher.MVVMDemo.Day01Core.ViewModel;
using GalaSoft.MvvmLight.Views;
using GalaSoft.MvvmLight.Ioc;
namespace Catcher.MVVMDemo.Day01DroidByMvvmLight
{
public static class App
{
private static ViewModelLocator _locator;
public static ViewModelLocator Locator
{
get
{
if (_locator == null)
{
var nav = new NavigationService();
nav.Configure("Main", typeof(MainActivity)); SimpleIoc.Default.Register<INavigationService>(() => nav);
//the dialog
SimpleIoc.Default.Register<IDialogService, DialogService>();
_locator = new ViewModelLocator();
}
return _locator;
}
}
}
}

添加一个login.axml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="enter your name"
android:id="@+id/et_name" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="enter your password"
android:id="@+id/et_pwd" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login"
android:id="@+id/btn_login" />
</LinearLayout>

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

 using Android.App;
using Android.OS;
using Android.Widget;
using Catcher.MVVMDemo.Day01Core.ViewModel;
using GalaSoft.MvvmLight.Helpers;
using GalaSoft.MvvmLight.Views;
namespace Catcher.MVVMDemo.Day01DroidByMvvmLight
{
[Activity(Label = "Login", MainLauncher = true, Icon = "@drawable/icon")]
public class LoginActivity : ActivityBase
{
/// <summary>
/// the view model
/// </summary>
public LoginViewModel VM
{
get { return App.Locator.LoginViewModel; }
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.login);
EditText etName = FindViewById<EditText>(Resource.Id.et_name);
EditText etPassword = FindViewById<EditText>(Resource.Id.et_pwd);
Button btnLogin = FindViewById<Button>(Resource.Id.btn_login);
//binding
this.SetBinding(() => VM.Name, etName, () => etName.Text, BindingMode.TwoWay);
this.SetBinding(() => VM.Password, etPassword, () => etPassword.Text, BindingMode.TwoWay);
//button click
btnLogin.SetCommand("Click", VM.LoginCommand);
}
}
}

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

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

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

最后去掉MainActivity的MainLauncher=true

效果图如下:

第四个例子(UWP):

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

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

通过Page.DataContext设置了ViewModel

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

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

        protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
} Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(LoginPage), e.Arguments);
} Window.Current.Activate();
//
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
var navigationService = new NavigationService();
navigationService.Configure("Login", typeof(LoginPage));
navigationService.Configure("Main", typeof(MainPage));
SimpleIoc.Default.Register<INavigationService>(() => navigationService);
SimpleIoc.Default.Register<IDialogService, DialogService>();
}
}

效果图:

0x04 简单总结

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

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

 namespace GalaSoft.MvvmLight.Views
{
public class ActivityBase : Activity
{
public ActivityBase();
public static ActivityBase CurrentActivity { get; }
public static void GoBack();
protected override void OnResume();
}
}

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

    public abstract class ViewModelBase : ObservableObject, ICleanup

     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. SQL Server最近怎样了

    SQL Server最近怎样了 又到年终了,大家都作最后冲刺 最近园子里真的多了很多口水帖,无论大家争论得多么激烈,时间依然滴答滴答地过,争论完之后我们依然要继续埋头苦干 为年终奖.为明年做准备 这里 ...

  2. CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09)

    事件的结果 经过多天的思考及忙碌的开发及测试,CYQ.Data 终于在UI上全面支持WPF,至此,CYQ.Data 已经可以方便支持wpf的开发,同时,框架仍保留最低.net framework2.0 ...

  3. ABP理论学习之依赖注入

    返回总目录 本篇目录 什么是依赖注入 传统方式产生的问题 解决办法 依赖注入框架 ABP中的依赖注入基础设施 注册 解析 其他 ASP.NET MVC和ASP.NET Web API集成 最后提示 什 ...

  4. ASP.NET Core 1.0中的管道-中间件模式

    ASP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middleware)的方式注册在管道中.显而易见这样的设计非常松耦合 ...

  5. CSS3魔法堂:CSS3滤镜及Canvas、SVG和IE滤镜替代方案详解

    一.前言    IE特有的滤镜常常作为CSS3各种新特性的降级处理补充,而Adobe转向HTML5后与Chrome合作推出CSS3的Filter特性,因此当前仅Webkit内核的浏览器支持CSS3 F ...

  6. jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)

    Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...

  7. 小型文件数据库 (a file database for small apps) SharpFileDB

    小型文件数据库 (a file database for small apps) SharpFileDB For english version of this article, please cli ...

  8. SQL语句全

    创建数据库 创建之前判断该数据库是否存在 if exists (select * from sysdatabases where name='databaseName') drop database ...

  9. PHP分布式中Redis实现Session

    方法一:找到配置文件php.ini,修改为下面内容,保存并重启服务 session.save_handler = redis session.save_path = "tcp://127.0 ...

  10. KnockoutJS 3.X API 第七章 其他技术(5) 使用其他事件处理程序

    在大多数情况下,数据绑定属性提供了一种干净和简洁的方式来绑定到视图模型. 然而,事件处理是一个常常会导致详细数据绑定属性的领域,因为匿名函数通常是传递参数的推荐技术. 例如: <a href=& ...