• Windows Phone 十一、MVVM模式


    MVVM 模式介绍

    模型-视图-视图模型 (MVVM) 是一种用来分离 UI 和非 UI 代码的应用设计模式

    MVVM – 模型(Model)

    MVVM 中的 Model 与 MVC 中的一致,用于封装业务逻辑以及数据处理。

    Model 不依赖 View 和 ViewModel,可以独立存在,也就是说模型不关心自身被谁操作和展示。

    Model 中不允许有任何跟界面相关的逻辑,比如操作界面上的控件。

    通常在实际开发过程中 Model 可以再被划分成 Model 和 Service,区分业务和数据。

    MVVM – 视图(View)

    视图仅仅负责界面展示。

    通过 DataContext(数据上下文)进行数据绑定。

    不允许直接与 Model 交互。

    可以通过绑定 Comand 来调用 ViewModel 的行为。

    Command 是 View 到 ViewModel 的单向通行。

    用户在 View 中触发事件,在 ViewModel 中处理。

    MVVM – 视图模型(ViewModel)

    ViewModel 是对 View 的抽象

    视图模型包括界面模型数据和 Command 事件响应。

    是 View 和 Model 的桥梁,是对 Model 的包装和抽象。

    实现视图模型需要让类型实现 INotifyPropertyChanged 接口,用于实现属性和集合的变更通知,使用户在 View 上所做的操作可以实时通知到视图模型。

    MVVM - Demo

    利用 MVVM 实现一个计算器;

    要求界面和业务逻辑完全剥离;

    比如我们可以更改界面展示形式,功能仍然相同;

    第一步:先对页面进行抽象(建模)

    第二步:让视图模型实现INotifyPropertyChanged接口

    第三步:后台代码中声明一个视图模型属性交给当前数据上下文

    第四步:前台数据绑定

    第五步:定义Command命令

     1 <Page
     2     x:Class="MyJiSuanQi.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:MyJiSuanQi"
     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     DataContext="{Binding ViewModel,RelativeSource={RelativeSource Mode=Self}}"
    10     Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    11 
    12     <StackPanel>
    13         <Slider
    14             Header="参数1"
    15             Value="{Binding Parameter1,Mode=TwoWay}"/>
    16         <!--<TextBox 
    17             x:Name="txtP1" 
    18             Header="参数1"
    19             Text="{Binding Parameter1,Mode=TwoWay}"/>-->
    20         <TextBox 
    21             x:Name="txtP2"
    22             Header="参数2"
    23             Text="{Binding Parameter2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    24         <AppBarButton 
    25             x:Name="btnAdd" 
    26             Icon="Italic"
    27             Label="Except"
    28             Command="{Binding ExceptCommand}"
    29             CommandParameter="{Binding}"/>
    30         <TextBox
    31             x:Name="txtResult"
    32             Header="结果"
    33             Text="{Binding Result,Mode=OneWay}"/>
    34     </StackPanel>
    35 </Page>
      1 namespace MyJiSuanQi
      2 {
      3     /// <summary>
      4     /// 可用于自身或导航至 Frame 内部的空白页。
      5     /// </summary>
      6     public sealed partial class MainPage : Page
      7     {
      8         public MainPageViewModel ViewModel { get; set; }
      9         public MainPage()
     10         {
     11             ViewModel = new MainPageViewModel();
     12             this.InitializeComponent();
     13 
     14             this.NavigationCacheMode = NavigationCacheMode.Required;
     15         }
     16 
     17         /// <summary>
     18         /// 在此页将要在 Frame 中显示时进行调用。
     19         /// </summary>
     20         /// <param name="e">描述如何访问此页的事件数据。
     21         /// 此参数通常用于配置页。</param>
     22         protected override void OnNavigatedTo(NavigationEventArgs e)
     23         {
     24             // TODO: 准备此处显示的页面。
     25 
     26             // TODO: 如果您的应用程序包含多个页面,请确保
     27             // 通过注册以下事件来处理硬件“后退”按钮:
     28             // Windows.Phone.UI.Input.HardwareButtons.BackPressed 事件。
     29             // 如果使用由某些模板提供的 NavigationHelper,
     30             // 则系统会为您处理该事件。
     31         }
     32         //第一步:先对页面进行抽象(建模)
     33         //第二步:让视图模型实现INotifyPropertyChanged接口
     34         //第三步:后台代码中声明一个视图模型属性交给当前数据上下文
     35         //第四步:前台数据绑定
     36         //第五步:定义Command命令
     37         private void btnAdd_Click(object sender, RoutedEventArgs e)
     38         {
     39             //var d1 = double.Parse(txtP1.Text);
     40             //var d2 = double.Parse(txtP2.Text);
     41             //txtResult.Text = (d1 + d2).ToString();
     42             ViewModel.Result = ViewModel.Parameter1 + ViewModel.Parameter2;
     43         }
     44     }
     45     public class MainPageViewModel : INotifyPropertyChanged
     46     {
     47         public MainPageViewModel()
     48         {
     49             AddCommand = new AddCommand();
     50             ExceptCommand = new ExceptCommand();
     51         }
     52         public double Parameter1 { get; set; }
     53         private double parameter2;
     54         //影响当前命令是否可以被执行的依据
     55         public double Parameter2
     56         {
     57             get { return parameter2; }
     58             set
     59             {
     60                 if (parameter2 == value)
     61                 {
     62                     return;
     63                 }
     64                 parameter2 = value;
     65                 //通知命令对象重新判断是否可以执行
     66                 ExceptCommand.OnCanExecuteChanged();
     67             }
     68         }
     69         //public double Result { get; set; }
     70         private double result;
     71         public double Result
     72         {
     73             get { return result; }
     74             set { result = value; OnPropertyChanged("Result"); }
     75         }
     76         public ICommand AddCommand { get; set; }
     77         public ExceptCommand ExceptCommand { get; set; }
     78         private void OnPropertyChanged(string propertyName)
     79         {
     80             if (PropertyChanged != null)
     81             {
     82                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
     83             }
     84         }
     85         public event PropertyChangedEventHandler PropertyChanged;
     86     }
     87     //命令对象必须实现ICommand接口
     88     public class AddCommand : ICommand
     89     {
     90         //判断当前命令对象是否可以被执行
     91         public bool CanExecute(object parameter)
     92         {
     93             throw new NotImplementedException();
     94         }
     95 
     96         public event EventHandler CanExecuteChanged;
     97         //如何执行
     98         public void Execute(object parameter)
     99         {
    100             var model = parameter as MainPageViewModel;
    101             model.Result = model.Parameter1 + model.Parameter2;
    102         }
    103     }
    104     //命令对象必须实现ICommand接口
    105     public class ExceptCommand : ICommand
    106     {
    107         //判断当前命令对象是否可以被执行
    108         public bool CanExecute(object parameter)
    109         {
    110             var model = parameter as MainPageViewModel;
    111             return model != null && model.Parameter2 != 0;
    112         }
    113         //当CanExecute判断依据发生变化时,触发事件
    114         public event EventHandler CanExecuteChanged;
    115         public void OnCanExecuteChanged()
    116         {
    117             if (CanExecuteChanged != null)
    118                 CanExecuteChanged(this, EventArgs.Empty);
    119         }
    120         //如何执行
    121         public void Execute(object parameter)
    122         {
    123             var model = parameter as MainPageViewModel;
    124             model.Result = model.Parameter1 / model.Parameter2;
    125         }
    126     }
    127 }
    MVVM 模式优点

    低耦合:View 可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的 View 上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。

    可重用性:可以把一些视图的逻辑放在 ViewModel 里面,让很多View重用这段视图逻辑。

    独立开发:开发人员可以专注与业务逻辑和数据的开发(ViewModel)。设计人员可以专注于界面(View)的设计。

    可测试性:可以针对ViewModel来对界面(View)进行测试。

  • 相关阅读:
    Python 中的 __str__ 与 __repr__ 到底有什么差别
    02 LeetCode---链表相加
    01 LeetCode---两数之和
    python 数据结构一 之 线性表
    来自C++的"Const式"傲娇
    string 与 char 字符串区别-1
    超级有爱的并查集入门
    多项式求解
    竞码编程-蓝桥杯模拟赛4-D题
    树的直径-蓝桥杯大臣的旅费
  • 原文地址:https://www.cnblogs.com/includeling/p/4591440.html
Copyright © 2020-2023  润新知