zoukankan      html  css  js  c++  java
  • C# 实践之 基于WPF的mvvm模型,使UI独立,逻辑可测

    背景:

      需求:实现从数据库读取级联表指定字段数据,并展示到前台界面。

      VM层做业务逻辑层,每页最多获取2条数据。

      View层只有数据表格,上一页与下一页按钮,且上一页与下一页在特定条件下不可用。

     (转载请注明来源:cnblogs coder-fang)

                          解决方案结构如下:

        • 项目结构:       
        • WPFTest:主要是界面显示数据(V层),ViewModel是wpftest的VM层,unittest做vm及数据的测试项目。
        • 示例用的数据结构如图:

           

    1. 创建类库VM项目,为了简化,这里将M层与VM层放到了同一项目中,首先在VM中使用EF框架生成相关数据实体与context(EF自行查阅,这里不多介绍),即M层,项目目录如下:
    2. 为了使V层(展示层)与核心业务控制解耦,需要在VM层实现对业务的控制,建通用Command类,代码如下:
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Windows.Input;
      
      namespace ViewModels
      {
          public class Command :ICommand
          {
              private Action methodToExecute = null;
              private Func<bool> methodCanExecute = null;
      
              public Command(Action methodToExecute, Func<bool> methodCanExecute)
              {
                  this.methodToExecute = methodToExecute;
                  this.methodCanExecute = methodCanExecute;           
              }
              
              public void Execute(object parameter)
              {
                  this.methodToExecute();
              }
              public bool CanExecute(object parameter)
              {
                  if (this.methodCanExecute == null)
                  {
                      return true;
                  }
                  else
                  {
                      return this.methodCanExecute();
                  }
              }
              
              public event EventHandler CanExecuteChanged;
              public void RaseCanExecuteChangedEvent()
              {
                  if (this.CanExecuteChanged != null)
                  {
                      this.CanExecuteChanged(this, EventArgs.Empty);
                  }
              }
          }
      }
      View Code

      这里的command主要参数为命令调用的函数委托,是否可执行的函数委托

    3. 创建DatagridVM,是显示层主要的数据提供者,与业务控制者,代码如下:
      using System;
      using System.Collections.Generic;
      using System.Collections.ObjectModel;
      using System.Collections.Specialized;
      using System.ComponentModel;
      using System.Linq;
      using System.Text;
      using System.Windows.Input;
      using ViewModels;
      
      namespace ViewModels
      {
          public class GridMember
          {
              public string Name { get; set; }
              public string Role { get; set; }
              public string Depart { get; set; }
          }
          
          public class DatagridVM : INotifyPropertyChanged
          {
              
              public event PropertyChangedEventHandler PropertyChanged;        
      
              private List<GridMember> _griddata;       
      
              public Command preCmd {get;private set;}
              public Command nextCmd { get; private set; }
      
              public Action<String> errCallback { get; set; }
      
              private int _curpage = 1;
              private int _total = 0;
      
              public void getData()
              {
                  using (dbEntities ctx = new dbEntities())
                  {
                      try
                      {
                          Total = ctx.user.Count();
                          var users = (from c in ctx.user orderby c.id select new GridMember{ Name = c.username, Role = c.Role1.rolename, Depart = c.deprtment.departname }).Skip((CurPage - 1) * 2).Take(2);
                          foreach (var item in users)
                          {
                              Console.WriteLine(item.Name);
                          }
                          this.GridData = users.ToList();
                      }
                      catch (Exception e)
                      {
      
                          if (errCallback != null)
                              errCallback(e.Message+"
      "+e.StackTrace);
                      }
                      
                  }
              }
              public List<GridMember> GridData
              {
                  get { return _griddata; }
                  set { _griddata = value; OnPropertyChanged("GridData"); }
              }
              public int CurPage
              {
                  get { return _curpage; }
                  set { _curpage = value;
                      OnPropertyChanged("CurPage");
                      preCmd.RaseCanExecuteChangedEvent();
                      nextCmd.RaseCanExecuteChangedEvent();
                  }
              }
      
              public int Total
              {
                  get { return _total; }
                  set { _total = value; OnPropertyChanged("Total"); }
              }
              public DatagridVM()
              {
                  preCmd = new Command(() =>
                  {
                      CurPage--;
                      getData();
                  }, () => { return (bool)(CurPage > 1); });
                  nextCmd = new Command(() =>
                  {
                      CurPage++;
                      getData();
                  }, () => { return (bool)(CurPage * 2 < Total); });
                  getData();
              }
              
              protected void OnPropertyChanged(string name)
              {
                  PropertyChangedEventHandler handler = PropertyChanged;
                  if (handler != null)
                      handler(this, new PropertyChangedEventArgs(name));
              }
      
             
          }
      }
      View Code

      注:其中GridMember为VM需要从数据库中查询的(多表联合后)数据字段,也是显示层要显示的字段,且创建了两个命令,用来实现上一页与下一页的业务逻辑,在CurPage改变时,需要发出一个事件,即相关命令更新自己的可执行状态。

    4. 至此,VM层已完成,下面创建显示层,创建简单的WPF窗口项目:                                                       
    5. 此项目需引用ViewModels,创建新窗口,Datagrid.xaml,界面代码如下:

      <Window x:Class="WPFTest.Datagrid"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:ViewModels;assembly=ViewModels"                    
              Title="Datagrid" Height="311.417" Width="528.358">
          
          <Window.Resources>        
              <local:DatagridVM x:Key="VM"/>                
          </Window.Resources>
          
          <Grid Name="Grid" DataContext="{StaticResource VM}">                      
              <Grid.RowDefinitions>
                  <RowDefinition Height="auto"></RowDefinition>
                  <RowDefinition Height="*"></RowDefinition>
              </Grid.RowDefinitions>
              <StackPanel Grid.Row="0" Margin="10" Orientation="Horizontal" >
      
                  <Button Name="Pre" Command="{Binding Path=preCmd}" >上一页</Button>
                  <Button Name="Next" Command="{Binding Path=nextCmd}" >下一页</Button>
                  
              </StackPanel>
              <DataGrid Name="usersGrid" Grid.Row="1"  ItemsSource="{Binding  Path=GridData}"></DataGrid>
          </Grid>
      </Window>
      View Code

      注意这里的两个button,并没有实现click,反而使用命令绑定,自动调用了VM的执行函数,自动更新可执行状态,这就解耦了界面与业务。

    6. 整个界面已完成,是的,UI只需要编辑这个文件即可,已经将业务与UI分离了出来。
    7. 运行效果:首页:最后一页:

       下面进行对VM层的单元测试

    8.  创建C#的单元测试项目,并引用viewmodel:

    9. 创建DataGridVMTest,代码如下:

      using System;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using ViewModels;
      using System.Collections.Generic;
      using System.Linq;
      
      
      namespace UnitTest
      {
          [TestClass]
          public class DataGridVMTest
          {
              [TestMethod]
              public void testFunc()
              {
                  DatagridVM vm = new DatagridVM();
                  vm.errCallback = (e) => { Console.WriteLine("出现异常:"+e); };
                  Assert.AreEqual(vm.CurPage, 1);
                  
                  Assert.AreEqual(vm.Total, 7);
                  Assert.IsFalse(vm.preCmd.CanExecute(null));
                  Assert.IsTrue(vm.nextCmd.CanExecute(null));
                  vm.CurPage = 3;
                  Assert.IsTrue(vm.preCmd.CanExecute(null));
                  Assert.IsTrue(vm.nextCmd.CanExecute(null));
      
                  vm.nextCmd.Execute(null);
                  Assert.IsTrue(vm.preCmd.CanExecute(null));
                  Assert.IsFalse(vm.nextCmd.CanExecute(null));
                  
      
                              
                  Assert.AreEqual(vm.GridData.Count, 1);
                  
      
      
              }
          }
      }
      View Code

      注:数据库中有7条记录,每页显示2条,所以在testFunc中,分别测试不同页码时,preCmd与nextCmd的可执行状态,且在最后一页时测试获取数据的Count

    10. 执行结果:

       本次实践已完成。

    总结:MVVM前期需要花费一定的工作量,但带来的效果是显而易见的,当然,是否使用MVVM进行开发还需要很多其它因素的参考,希望大家灵活运用。

                

  • 相关阅读:
    Spring Security 3.2.x与Spring 4.0.x的Maven依赖管理
    文件下载-SpringMVC中測试
    Redhat 6.3中syslog信息丢失
    HDU2586 How far away ?(LCA模板题)
    android开机启动应用和服务
    swift 3.0基本数据语法
    swift 获取UI上某点点颜色
    Hello_IOS ios开发transform属性
    CGAffineTransformMakeTranslation和CGAffineTransform
    iOS 原生地图(MapKit、MKMapView)轨迹渐变
  • 原文地址:https://www.cnblogs.com/coder-fang/p/8134455.html
Copyright © 2011-2022 走看看