Silverlight - 檢視模型



本章我們將探討Silverlight軟體開發中一項重要的技術:使用檢視模型

  • 檢視模型是一個關鍵部分,它透過將檢視與模型分開來引入一種稱為分離表示的技術。

  • 檢視模型提供了一種實現分離表示的方法,我們將看到它們如何利用Silverlight的資料繫結來減少使用者介面中所需的程式碼量。

UI開發挑戰

檢視模型旨在解決開發使用者介面軟體時經常出現的一些問題。也許最重要的一點是,使用者介面程式碼通常難以進行測試,尤其難以進行自動單元測試。還有一些程式碼質量問題會影響程式碼的持續靈活性和可維護性。

  • 如果您遵循Visual Studio設計工具引導您的最便捷路徑,您最終可能會在程式碼隱藏中放入過多的程式碼。

  • 通常會看到大量應用程式功能新增到程式碼隱藏中。

  • 很少有開發人員會實際計劃將業務邏輯放入使用者介面類中,但由於這就是Visual Studio放置事件處理程式的地方,因此它成為完成任務的一個過於方便的地方。

  • 人們普遍認為,如果類具有明確定義且責任範圍合理的職責,則軟體更容易開發和維護。

  • 程式碼隱藏的工作是根據需要直接與構成使用者介面的物件進行互動。

  • 一旦您開始在其中放置關於應用程式如何執行的決策程式碼,就會導致問題。

  • 應用程式邏輯不僅會流入應該關注使用者介面的程式碼,一些開發人員還會開始依賴控制元件和其他使用者介面物件來儲存重要的應用程式狀態。

  • 模型只儲存資料,檢視只儲存格式化後的資料,控制器(ViewModel)充當兩者之間的聯絡員。控制器可能會接收來自檢視的輸入並將其放入模型中,反之亦然。

MVC

分離表示

為了避免將應用程式邏輯放入程式碼隱藏或XAML中而導致的問題,最好使用稱為分離表示的技術。使XAML和程式碼隱藏具有與使用者介面物件直接互動所需的最小功能,使用者介面類還包含複雜互動行為、應用程式邏輯以及其他所有內容的程式碼,如下面的左側所示。

Separated Presentation

分離表示的重要特性:

  • 使用分離表示,使用者介面類會更簡單。當然它有XAML,但程式碼隱藏儘可能少。

  • 應用程式邏輯位於一個單獨的類中,通常稱為模型

  • 許多開發人員嘗試使用資料繫結將XAML中的元素直接連線到模型中的屬性。

  • 問題是模型完全關注應用程式的功能,而不關注使用者如何與應用程式互動。

  • 大多數使用者介面都有一些不屬於應用程式模型的狀態。例如,如果您的使用者介面使用拖放,則某些內容需要跟蹤諸如當前拖動專案的所在位置、在拖動到可能的放置目標時其外觀應如何變化以及這些放置目標在拖動專案經過時也可能如何變化等方面。

  • 這種狀態可能會變得非常複雜,需要進行徹底的測試。

  • 實際上,您通常希望在使用者介面和模型之間放置另一個類。它有兩個重要的作用。

    • 首先,它會為特定使用者介面檢視調整您的應用程式模型。

    • 其次,它是任何非平凡互動邏輯所在的地方,我的意思是讓您的使用者介面按您想要的方式執行所需的程式碼。

模型/檢視/檢視模型

檢視模型是分離表示方法的一個示例,但讓我們明確說明每一層中究竟是什麼樣的東西。有三層:

  • 模型
  • 檢視
  • 檢視模型

模型

這是一個由普通的C#類組成的經典物件模型,它與使用者介面沒有直接關係。

您通常期望您的模型程式碼能夠在沒有對任何使用者介面庫的引用的情況下編譯。實際上,您可能能夠使用完全相同的原始碼並將其編譯到Silverlight應用程式、普通的.NET控制檯應用程式甚至伺服器端Web程式碼中。

模型中的型別應表示您的應用程式使用的概念。

檢視

檢視通常是UserControl,它可能是您的MainPage,也可能只是您頁面的一部分。

在大多數Silverlight應用程式中,將使用者介面拆分為較小的部分來定義每個部分的UserControl或View是一個好主意。

Silverlight應用程式在這方面並非獨一無二。顯然特定於Silverlight的是View。使用者介面的粒度越細,效果越好。您不太可能遇到其他開發人員處理相同檔案的麻煩,保持簡潔自然會阻止導致義大利麵條式程式碼的捷徑。

例如,定義一個檢視來表示列表中的單個專案是很常見的。

檢視模型

最後,對於每個檢視,您都編寫一個檢視模型。所以,這是檢視模型類的一個重要特性。

它存在於為特定的檢視服務。檢視模型專門用於特定的事物呈現方式,例如列表中顯示的特定資料項。

這就是為什麼它被稱為檢視模型;它專門為特定檢視調整底層模型。與模型一樣,檢視模型也是一個普通的C#類。它不需要派生自任何特定型別。

碰巧的是,一些開發人員發現將一些常用功能放入基檢視模型類中很方便,但模式並不需要這樣做。特別是,您的檢視模型不會派生自任何Silverlight特定型別。但是,與模型不同的是,它可以在其屬性中使用Silverlight型別。

例如,您的檢視模型可能會選擇僅在特定條件下顯示使用者介面的某些部分,因此您可能會提供System.Windows.Visibility型別的屬性,這是Silverlight元素對其Visibility屬性使用的型別。這使得可以直接將元素(例如面板)的可見性繫結到檢視模型成為可能。

示例

讓我們來看一個簡單的例子,在這個例子中我們將使用模型-檢視-檢視模型(MVVM)方法。

步驟1 - 建立一個新的Silverlight應用程式專案SilverlightMVVMDemo

步驟2 - 將三個資料夾(Model、ViewModel和Views)新增到您的專案中,如下所示。

SilverlightMVVMDemo

步驟3 - 在Model資料夾中新增一個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 - 在ViewModel資料夾中新增另一個StudentViewModel類,並貼上以下程式碼。

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 - 透過右鍵單擊Views資料夾並選擇新增新項…來新增Silverlight使用者控制元件

Silverlight User Control

步驟6 - 點選新增。現在您將看到XAML檔案。將以下程式碼新增到包含不同UI元素的StudentView.xaml檔案中。

<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更新檢視

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 - 編譯並執行上述程式碼後,您將在網頁上看到以下輸出。

Add Student View

UI與檢視模型

MVVM方法中最難的部分之一是確定分界線應該在哪裡。哪些東西屬於哪裡並不總是顯而易見的。

  • 特別是,一些使用者介面元素提供了根據嚴格的檢視來看,可能屬於檢視模型的功能。

  • 一般來說,並非所有在檢視中實現的行為都那麼檢視模型友好。

  • 部分原因是沒有標準的方法來打包檢視模型行為以供重用,特別是如果您想使用設計環境(如Visual Studio或Blend)時。

MVVM的優點

MVVM具有以下優點:

  • 分離表示關注點(檢視、檢視模型、模型)

  • 簡潔易於測試和管理的程式碼。可以在單元測試中包含表示層邏輯。

  • 沒有程式碼隱藏程式碼,因此表示層和邏輯是鬆散耦合的。

  • 更好的資料繫結方式。

MVVM的缺點

對於簡單的UI,MVVM可能過於複雜。當我們有複雜的資料繫結時,除錯會比較困難。

廣告