在界面开发的过程中,为了提高多人协作能力和系统的可测试性,需要引入一些开发模式,本文针对常见的几个界面模式进行汇总,在以后使用时作为一个参考。
A full branch of design patterns is dedicated to building UIs . The best-known UI design patterns are the Model View Controller (MVC), the Model View Presenter (MVP), and the Presentation Model (PM) patterns that you encountered in the book’s introduction as forebears of the MVVM . Other UI patterns exist as well . These are subpatterns of the MVC and MVP patterns, but they are rarely implemented any more with the .NET Framework .
MVC
Ø The Model represents the data in the application in a logical way; it is in charge of carrying the data and making other objects aware of data changes .
Ø The View is the graphical representation of the Model; it is responsible for displaying the Model data in suitable form .
Ø The Controller is the orchestrator of this pattern; it is in charge of intercepting user input (mouse and keyboard) and interacting with the Model and/or the View .
实例
Model
/// <summary>
/// Simple Model that represents an Employee entity
/// </summary>
public class Employee
{
/// <summary>
/// The First Name
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// The Last Name
/// </summary>
public string LastName { get; set; }
/// <summary>
/// The Company name
/// </summary>
public string Company { get; set; }
}
Controller
///<summary>
/// The Controller in charge of displaying the Views
///</summary>
public class HomeController : Controller
{
/// <summary>
/// An action that renders the Index View
/// </summary>
publicActionResultDisplayEmployee()
{
var model = new Employee
{
FirstName = "John",
LastName = "Smith",
Company = "Microsoft"
};
return View(model);
}
}
View
<h2>DisplayEmployee</h2>
<fieldset>
<legend>Fields</legend>
<div class="display-label">FirstName</div>
<div class="display-field"><%: Model.FirstName %></div>
<div class="display-label">LastName</div>
<div class="display-field"><%: Model.LastName %></div>
<div class="display-label">Company</div>
<div class="display-field"><%: Model.Company %></div>
</fieldset>
使用场景和优缺点
The MVC pattern fits web applications best .
its capacity to display the same Model in different Views and the ability to change the way the View renders without affecting the Model (which is unaware of the Views) .
Another strength is its testability . Because the View is also unaware of the Model, the Controller can simply use a mockup Model for testing purposes .
MVC is a complex pattern, and it is event-driven; the Controller reacts to changes made by users, about which it notifies the Model and the View .
In addition, updating MVC can can consume a considerable amount of resources, because the View must be alerted and updated through the Controller for every update . Some of the modern frameworks such as ASP .NET MVC do not apply the MVC pattern in its original form—another reason why this pattern a good fit for both client and web applications .
In addition, the original MVC pattern, as it was conceived, would not be a good fit for new UI technologies such as WPF and Silverlight . With that said . I would also like to specify that there are many modern UI design patterns today that are wrongly identified with the name “MVC pattern,” but these are not the original MVC pattern; they’re substitutes for the original pattern .
MVP Pattern
Like the MVC, the MVP has three components, but with some differences:
Ø The Model is the same as in MVC . It represents any business entity with associated data and business logic .
Ø The View is the graphical interface in charge of rendering the data . It directly references the Presenter so that it can delegate to it the interpretation of all user interactions .
Ø The Presenter drives the UI logic; it knows both the View (through an interface) and the Model . It updates the View based on change notifications from the Model and updates the Model based on change notifications from the View . This is the object that encapsulates the presentation logic, and it usually sets property values and calls methods on the View rather than using a binding engine
与MVC差别
the View is passive and delegates any action to the corresponding Presenter .
the Presenter interacts with the View using a binding engine or a custom implementation of a binding engine if the UI technology doesn’t provide one .
The View and Model are not connected
实例
Model
同MVC
Presenter
/// <summary>
/// The Employee View contract
/// </summary>
public interface IEmployeeView
{
/// <summary>
/// TheFirstname
/// </summary>
stringFirstName { get; set; }
/// <summary>
/// TheLastname
/// </summary>
stringLastName { get; set; }
/// <summary>
/// The Company name
/// </summary>
string Company { get; set; }
}
/// <summary>
/// The Employee presenter in charge of
/// driving the UI logic
/// </summary>
public sealed class EmployeePresenter
{
/// <summary>
/// The current view
/// </summary>
privateIEmployeeView view;
/// <summary>
/// Initializes a new instance of the <see cref="EmployeePresenter"/> class.
/// </summary>
/// <param name="view">The view.</param>
publicEmployeePresenter(IEmployeeView view)
{
this.view = view;
}
/// <summary>
/// Initializes this instance.
/// </summary>
public void Initialize()
{
var model = new Employee
{
FirstName = "John",
LastName = "Smith",
Company = "Microsoft"
};
//Bind the Model to the View
UpdateViewFromModel(model);
}
/// <summary>
/// Updates the view from model.
/// </summary>
/// <param name="model">The model.</param>
private void UpdateViewFromModel(Employee model)
{
this.view.FirstName = model.FirstName;
this.view.LastName = model.LastName;
this.view.Company = model.Company;
}
}
View
/// <summary>
/// Concrete View.
/// </summary>
public partial class EmployeeView : Form, IEmployeeView
{
/// <summary>
/// The corresponding presenter
/// </summary>
privateEmployeePresenter presenter;
/// <summary>
/// Initializes a new instance of the <see cref="EmployeeView"/> class.
/// </summary>
publicEmployeeView()
{
InitializeComponent();
this.presenter = new EmployeePresenter(this);
this.presenter.Initialize();
}
/// <summary>
/// TheFirstname
/// </summary>
/// <value></value>
public string FirstName
{
get { return txtFirstname.Text; }
set { txtFirstname.Text = value; }
}
/// omitted
}
优缺点
the Presenter drives all logic;
the View can only make notifications about user interactions to the Presenter, which can then call methods and change data on the View and/or on the Model .
the round trip that occurs each time a user interacts with the View; the View must call a Presenter method, and then the Presenter must update the View .
all presentation logic and every binding process must go through the Presenter, so if you plan to adopt a Supervising Presenter pattern (more on this in the next section) in WPF or in Silverlight, you will wind up with a View that has the Model as its DataContext, plus a separate reference to the Presenter .
MVP isn’t appropriate for WPF or Silverlight because its passive implementation doesn’t use the power of XAML’s binding engine, and it’s not able to cleanly separate the XAML code that constructs the UI from the procedural C# needed in the View for it to know its corresponding Presenter .
the View has multiple references to maintain, which is difficult to test and requires more interfaces to maintain loose coupling .
MVVM
The MVVM pattern is an evolution of the PM pattern that has the three usual principal components:
a Model that represents the business entity (like the Employee class example),
a View that is the XAML UI,
the PM or View Model, which contains all the UI logic and the reference to the Model, so it acts as the Model for the View .
ViewModel和WPF,Silverlight的定制
One of these is the INotifyPropertyChanged interface, introduced with .NET Framework version 2 .0 . This interface implements a notification system that activates when the value of a property changes . It’s required in the ViewModel to make the binding engine of XAML work properly .
Another customization of the PM is the Command exposed by the interface ICommand, which is available for WPF and Silverlight . This specific Command can be bound to any XAML control and determines whether the control can or cannot execute a specific action . In WPF, this Command has a more powerful implementation through the Routed Command, which is a Command routed through the Visual Tree of a WPF UI .
A third customizable component is the DataTemplate, an XAML structure that defines how to render a specific ViewModel, or a specific state of the ViewModel . DataTemplate components are really views that are rendered at runtime by the WPF/Silverlight engine . They are particular type of Views that cannot contain any code behind because they are dynamically created .
Logically you are displaying a ViewModel or Model directly in the UI, but the view is conjured up at runtime and attached to the ViewModel or Model (through the data context) .
实例
Model
同Employee
ViewModel
/// <summary>
/// ViewModel for the Employee view
/// </summary>
public sealed class EmployeeViewModel : INotifyPropertyChanged
{
publicEmployeeViewModel()
{
var employee = new Employee
{
FirstName = "John",
LastName = "Smith",
Company = "Microsoft"
};
//Bind the model to the viewmodel
this.Firstname = employee.FirstName;
this.Lastname = employee.LastName;
this.Company = employee.Company;
}
#region INotifyPropertyChanged
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandlerPropertyChanged;
/// <summary>
/// Called when [property changed].
/// </summary>
/// <param name="name">The name.</param>
public void OnPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
/// <summary>
/// Private accessor for the Firstname
/// </summary>
private string firstname;
/// <summary>
/// Gets or sets the firstname.
/// </summary>
/// <value>The firstname.</value>
public string Firstname {
get
{
returnfirstname;
}
set
{
if (firstname != value)
{
firstname = value;
OnPropertyChanged("Firstname");
}
}
}
// omitted
}
View
<Window.DataContext>
<vm:EmployeeViewModel />
</Window.DataContext>
<StackPanel Orientation="Vertical">
<TextBlock>FirstName :</TextBlock>
<TextBox
Text="{Binding Path=Firstname,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
<TextBlock>Lastname :</TextBlock>
<TextBox
Text="{Binding Path=Lastname,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
<TextBlock>Company :</TextBlock>
<TextBox
Text="{Binding Path=Company,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
优缺点
the MVVM pattern is designed for use with WPF or Silverlight
one key advantage of adopting the MVVM pattern is that the View is an observer of theViewModel, which makes it easier to build the UI separately