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

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 == "123")
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的应用,可以看看具体的实现

http://mvvmlight.codeplex.com/SourceControl/latest#GalaSoft.MvvmLight/GalaSoft.MvvmLight.Platform (Android)/Helpers/Extensions.cs

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

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

时间: 2024-11-01 01:43:44

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

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

对现在的APP软件来说,基本上都会有一个Splash页面,类似大家常说的欢迎页面.启动界面之类的. 正常来说这个页面都会有一些相关的信息,比如一些理念,Logo,版本信息等 下面就来看看在Xamarin.Android是如何简单实现的吧. 一.新建一个空白Android项目 二.添加一个layout,splash.axml 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:

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

好几个月没写文章了,使用xamarin android也快接近两年,还有一个月职业生涯就到两个年了,从刚出来啥也不会了,到现在回头看这个项目,真jb操蛋(真辛苦了实施的人了,无数次吐槽怎么这么丑),怪自己太年轻了,还好是给指定行业的人使用. 重新学习思考之后,再看自己在项目中的某些实现的代码,的确不尽人意,甚至想骂自己. 项目经常改,改来该去,代码一直增加,一个fragment也没什么功能,接近1000行的代码,用region括起来,开看起来还挺整齐的,找的时候就凉了.究其原因,没有一种模式,所

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

一.前言 回忆到上篇 <Xamarin.Android再体验之简单的登录Demo> 做登录时,用的是GET的请求,还用的是同步, 于是现在将其简单的改写,做了个简单的封装,包含基于HttpClient和HttpWebRequest两种方式的封装. 由于对这一块还不是很熟悉,所以可能不是很严谨. 二.先上封装好的代码 1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Json

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

0x01 前言 对于现在大部分的APP,第一次打开刚安装或更新安装的APP都会有几个引导界面,通常这几个引导页是告诉用户 APP有些什么功能或者修改了什么bug.新增了什么功能等等等. 下面就用Xamarin.Android来简单实现一下.主要用到的是ViewPager,当然也就离不开Xamarin.Android.Support.v4 如果遇到不能编译的问题,可以参考Xamarin.Android之简单的抽屉布局的出错处理方案. 0x02 页面布局编写 新建一个Android项目 添加几个简单

Xamarin.Android绑定库分享

使用Xamarin.Android时,会用到各种第三方库,而这些库基本上是java编写的,要在Xamarin.Android中使用这些库,就需要通过Android Binding Project绑定对应的java库,然后在C#中使用.绑定时,可能需要编写相关的转换规则或者修改对应的java源代码,遇到问题时,可以到Xamarin的官网查看,也可以Google. Xamarin.Android绑定参考文档地址: http://developer.xamarin.com/guides/android

跨过几个坑,终于完成了我的第一个Xamarin Android App!

时间过得真快,距离上次发随笔又是一年多.作为上次发的我的第一个WP8.1应用总结的后继,这次同样的主要功能,改为实现安卓版APP.前几个月巨硬收购Xamarin,把Xamarin集成到VS里了,大大方便了我广大.net码农.由于年初脱了WP的坑,换了个安卓低端机,想着什么时候装Xamarin开发个App玩玩. 上个月笔记本100G的C盘莫名其妙快满了,趁着重装系统的机会,安装了VS2015 with sp3,下载开发Android App需要的各种东东.这里要感谢[C#]VS2015开发环境的安

Xamarin.Android开发实践(十七)

Xamarin.Android之定位 一.前言 打开我们手中的应用,可以发现越来越多的应用使用了定位,从而使我们的生活更加方便,所以本章我们将学习如何在Xamarin中进行定位的开发. 二.准备工作 因为我们的虚拟机是运行在电脑本地的,自然就没法进行定位了,但是我们可以借助DDMS这个工具帮助我们去调试. 首先要确定你的Android SDK所在的目录,读者可以通过以下方式找到: 工具->选项 然后读者打开该文件夹下的tools文件夹,我们就可以看到里面有很多以bat结果的文件,这个时候我们打开

Xamarin.Android中使用ResideMenu实现侧滑菜单

上次使用Xamarin.Android实现了一个比较常用的功能PullToRefresh,详情见:Xamarin. Android实现下拉刷新功能 这次将实现另外一个手机App中比较常用的功能:侧滑菜单.通过搜索,发现有很多侧滑菜单,有仿手机QQ的侧滑菜单,有折叠的侧滑菜单,有SlidingMenu等,不过我还是比较喜欢 ResideMenu实现的效果,所以想通过Xamarin.Android的绑定实现该效果.这次实现该菜单遇到的问题比较多,花的时间也较多,花了三四个晚上才解决所有的问题.下面是

Xamarin.Android开发实践(十三)

Xamarin.Android之SQLite.NET ORM 一.前言 通过<Xamarin.Android之SQLiteOpenHelper>和<Xamarin.Android之ContentProvider>的 学习,我们已经掌握了如何使用特定于该平台的数据库操作.但是这样却和Xamarin所宣称的跨平台相违背了,因为这样我们就需要针对不同的平台编写不同 的代码,而本章将使用Github上的开源项目SQLite.NET去解决这个问题,从而可以实现跨平台,减少代码的重复. 关于该