Silverlight - 查看模型


在本章中,我们将研究 Silverlight 软件开发中的一项重要技术,即视图模型的使用。

  • 视图模型是一个关键部分,它通过将视图与模型分开来引入一种称为分离表示的技术。

  • 视图模型提供了实现分离表示的一种方法,我们将看到它们如何利用 Silverlight 的数据绑定来减少用户界面中所需的代码量。

UI 开发挑战

视图模型旨在解决开发用户界面软件时经常出现的某些问题。也许最重要的一点是用户界面代码通常很难进行不可分割的测试,尤其是自动化单元测试。还有代码质量问题可能会影响代码的持续灵活性和可维护性。

  • 如果您遵循 Visual Studio 设计工具引导您的阻力最小的路径,则最终可能会在后面的代码中放入过多的代码。

  • 大量应用程序功能被添加到后台代码中是很常见的。

  • 很少有开发人员真正计划将业务逻辑放入用户界面类中,但由于 Visual Studio 就是在其中放置事件处理程序的,因此它成为完成这些工作的一个非常方便的地方。

  • 人们普遍认为,如果类具有明确定义的、合理范围内的职责,那么软件就更容易开发和维护。

  • 隐藏代码的工作是在必要时直接与构成用户界面的对象进行交互。

  • 一旦您开始放置决定应用程序Behave方式的代码,这往往会导致问题。

  • 应用程序逻辑不仅可以流入应该与用户界面相关的代码中,而且一些开发人员开始依赖控件和其他用户界面对象来保存重要的应用程序状态。

  • 模型仅保存数据,视图仅保存格式化日期,控制器(ViewModel)充当两者之间的联络人。控制器可能从视图获取输入并将其放置在模型上,反之亦然。

多维控制器

分开演示

为了避免将应用程序逻辑放入代码隐藏或 XAML 中而导致的问题,最好使用称为分离表示的技术。用户界面类具有直接使用用户界面对象所需的最少 XAML 和隐藏代码,还包含复杂交互Behave、应用程序逻辑以及其他所有内容的代码,如下左侧所示。

分开演示

分离演示的重要特征 -

  • 通过分离的呈现,用户界面类变得更加简单。当然它有 XAML,但背后的代码只做实用的事情。

  • 应用程序逻辑属于一个单独的类,通常称为模型

  • 许多开发人员尝试使用数据绑定将 XAML 中的元素直接连接到模型中的属性。

  • 问题是模型完全关心应用程序做什么,而不关心用户如何与应用程序交互。

  • 大多数用户界面都有一些不属于应用程序模型的状态。例如,如果您的用户界面使用拖放操作,则需要跟踪诸如被拖动的项目现在所在的位置、当其在可能的放置目标上移动时其外观应如何变化以及这些放置目标可能如何变化等信息。当项目被拖到它们上面时会发生变化。

  • 这种状态可能会变得异常复杂,并且需要进行彻底的测试。

  • 在实践中,您通常需要在用户界面和模型之间放置一些其他类。这有两个重要作用。

    • 首先,它使您的应用程序模型适应特定的用户界面视图。

    • 其次,它是任何重要交互逻辑所在的地方,我的意思是让用户界面按照您想要的方式运行所需的代码。

模型/视图/ViewModel

视图模型是分离表示方法的一个示例,但让我们清楚每一层中到底有什么类型的东西。有三层 -

  • 模型
  • 看法
  • 视图模型

模型

这是一个经典的对象模型,由与用户界面没有直接关系的普通 C# 类组成。

您通常希望模型代码能够在不引用任何用户界面库的情况下进行编译。事实上,您可能能够获取完全相同的源代码并将其编译成 Silverlight 应用程序、普通的 .NET 控制台应用程序,甚至服务器端 Web 代码。

模型中的类型应该代表您的应用程序使用的概念。

看法

视图通常是一个用户控件,它可能是您的主页,也可能只是页面的某些部分。

在大多数 Silverlight 应用程序中,最好将用户界面分成小块,为每个块定义一个 UserControl 或 View。

Silverlight 应用程序在这方面并不是独一无二的。显然 Silverlight 特有的东西就是视图。用户界面的粒度越细,效果就越好。您不仅不太可能被其他处理相同文件的开发人员绊倒,而且使事情保持小而简单自然会阻止导致类似意大利面条的代码的捷径。

例如,定义视图来表示列表中的单个项目是很常见的。

视图模型

最后,为每个View编写一个ViewModel因此,这是ViewModel类的重要功能之一。

它的存在是为了服务于特定的视图。ViewModel专门用于呈现事物的特定方式,例如列表中出现的特定数据项。

这就是它被称为ViewModel 的原因;它特别针对特定视图调整底层模型。与 Model 一样,ViewModel也是一个普通的 C# 类。它不需要派生自任何特定类型。

碰巧,一些开发人员发现将一些常见功能放入 ViewModel 基类中很方便,但该模式并不要求这样做。特别是,您的ViewModel不派生自任何 Silverlight 特定类型。但是,与模型不同的是,它可以在其属性中使用 Silverlight 类型。

例如,您的 ViewModel 可能选择使用户界面的某些部分仅在某些条件下可见,因此您可能提供 System.Windows.Visibility 类型的属性,这是 Silverlight 元素用于其 Visibility 属性的类型。这使得将元素(例如面板)的可见性直接绑定到 ViewModel 成为可能。

例子

让我们看一个简单的示例,在该示例中我们将使用模型-视图-视图模型 (MVVM)方法。

步骤 1 - 创建一个新的 Silverlight 应用程序项目SilverlightMVVMDemo

步骤 2 - 将三个文件夹(Model、ViewModel 和 Views)添加到您的项目中,如下所示。

SilverlightMVVM演示

步骤 3 - 在模型文件夹中添加一个 StudentModel 类,并将以下代码粘贴到该类中。

using System.ComponentModel; 
 
namespace SilverlightMVVMDemo.Model { 

   public class StudentModel {} 
	
   public class Student : INotifyPropertyChanged { 
      private string firstName; 
      private string lastName;  
		
      public string FirstName { 
         get { return firstName; } 
			
         set {
            if (firstName != value) { 
               firstName = value; 
               RaisePropertyChanged("FirstName"); 
               RaisePropertyChanged("FullName"); 
            } 
         } 
      }
		
      public string LastName { 
         get { return lastName; } 
			
         set { 
            if (lastName != value) { 
               lastName = value; 
               RaisePropertyChanged("LastName"); 
               RaisePropertyChanged("FullName"); 
            } 
         } 
      }  
		
      public string FullName { 
         get { 
            return firstName + " " + lastName; 
         } 
      } 
		
      public event PropertyChangedEventHandler PropertyChanged; 
		
      private void RaisePropertyChanged(string property) { 
         if (PropertyChanged != null) { 
            PropertyChanged(this, new PropertyChangedEventArgs(property)); 
         } 
      } 
   } 
}

步骤 4 - 将另一个 StudentViewModel 类添加到 ViewModel 文件夹中并粘贴以下代码。

using SilverlightMVVMDemo.Model; 
using System.Collections.ObjectModel;
  
namespace SilverlightMVVMDemo.ViewModel { 

   public class StudentViewModel { 
	
      public ObservableCollection<Student> Students {  
         get;  
         set;  
      }  
		
      public void LoadStudents() { 
         ObservableCollection<Student> students = new ObservableCollection<Student>(); 
				
         students.Add(new Student { FirstName = "Mark", LastName = "Allain" }); 
         students.Add(new Student { FirstName = "Allen", LastName = "Brown" }); 
         students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" });
			
         Students = students; 
      } 
   } 
} 

步骤 5 -通过右键单击“视图”文件夹并选择“添加新项目...”来添加Silverlight 用户控件

Silverlight 用户控制

步骤 6 - 单击添加。现在您将看到 XAML 文件。将以下代码添加到StudentView.xaml文件中,该文件包含不同的 UI 元素。

<UserControl x:Class = "SilverlightMVVMDemo.Views.StudentView" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
   xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
   mc:Ignorable = "d" 
   d:DesignHeight = "300" d:DesignWidth = "400">
   
   <Grid x:Name = "LayoutRoot" Background = "White">
	
      <StackPanel HorizontalAlignment = "Left">
		
         <ItemsControl ItemsSource = "{Binding Path=Students}">
			
            <ItemsControl.ItemTemplate>
				
               <DataTemplate> 
					
                  <StackPanel Orientation = "Horizontal"> 
                     <TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}" 
                        Width = "100" Margin = "3 5 3 5"/> 
								
                     <TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"  
                        Width = "100" Margin = "0 5 3 5"/> 
								
                     <TextBlock  Text = "{Binding Path = FullName, Mode=OneWay}" 
                        Margin = "0 5 3 5"/> 
								
                  </StackPanel>
						
               </DataTemplate> 
					
            </ItemsControl.ItemTemplate>
				
         </ItemsControl> 
			
      </StackPanel> 
		
   </Grid> 
	
</UserControl>

步骤 7 - 现在将StudentView添加到MainPage.xaml文件中,如下所示。

<UserControl x:Class = "SilverlightMVVMDemo.MainPage" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
   xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
   xmlns:views = "clr-namespace:SilverlightMVVMDemo.Views" 
   mc:Ignorable = "d" 
   d:DesignHeight = "576.316" d:DesignWidth = "863.158"> 
   
   <Grid x:Name = "LayoutRoot" Background = "White"> 
      <views:StudentView x:Name = "StudentViewControl" Loaded = "StudentViewControl_Loaded"/> 
   </Grid> 
	
</UserControl>

步骤 8 - 这是MainPage.xaml.cs文件中Loaded事件的实现,它将更新ViewModel中的View

using System.Windows; 
using System.Windows.Controls; 
 
namespace SilverlightMVVMDemo { 

   public partial class MainPage : UserControl { 
	
      public MainPage() { 
         InitializeComponent();
      }
   } 
	
   private void StudentViewControl_Loaded(object sender, RoutedEventArgs e) { 
      SilverlightMVVMDemo.ViewModel.StudentViewModel 
      studentViewModelObject = new SilverlightMVVMDemo.ViewModel.
      StudentViewModel(); 
      studentViewModelObject.LoadStudents();  
      StudentViewControl.DataContext = studentViewModelObject;  
   } 
}

步骤 9 - 编译并执行上述代码后,您将在网页上看到以下输出。

添加学生视图

UI 与 ViewModel

MVVM 方法最困难的部分之一是确定分界线应该在哪里。哪些东西属于哪里并不总是显而易见的。

  • 特别是,一些用户界面元素提供的功能,根据严格的 View,可以说应该属于 ViewModel。

  • 一般来说,并非所有在View中实现的Behave都对ViewModel如此友好。

  • 部分原因是没有任何标准方法来打包 ViewModel Behave以供重用,特别是如果您想使用设计环境(例如 Visual Studio 或 Blend)。

MVVM 的优点

MVVM 具有以下优点 -

  • 分离表示关注点(View、ViewModel、Model)

  • 干净的可测试和可管理的代码。可以在单元测试中包含表示层逻辑。

  • 代码后面没有代码,因此表示层和逻辑是松散耦合的。

  • 更好的数据绑定方式。

MVVM 的缺点

对于简单的 UI,MVVM 可能有点大材小用。当我们有复杂的数据绑定时,调试会有点困难。