zoukankan      html  css  js  c++  java
  • 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的应用,可以看看具体的实现

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

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

  • 相关阅读:
    CoffeeScript介绍
    在ubuntu下安装rails
    NodeJS扫盲班
    sguID056681
    UVA11865 Stream My Contest(最小树形图)
    POJ1469COURSES(二分图最大匹配)
    UVA1494 Qin Shi Huang's National Road System(最小生成树)
    UVA11478 Halum(差分约束系统)
    二分图最大匹配总结
    POJ1466Girls and Boys(二分图最大独立集)
  • 原文地址:https://www.cnblogs.com/catcher1994/p/5521452.html
Copyright © 2011-2022 走看看