Silverlight - просмотр модели
В этой главе мы рассмотрим важный метод разработки программного обеспечения Silverlight - использование View Models.
В view model - это ключевая часть, которая вводит технику, называемую разделенным представлением, за счет отделения представления от модели.
View Models предлагают один способ достижения раздельного представления, и мы увидим, как они используют привязку данных Silverlight для уменьшения объема кода, необходимого в вашем пользовательском интерфейсе.
Проблемы разработки пользовательского интерфейса
View Modelsпредназначены для решения определенных проблем, которые часто возникают при разработке программного обеспечения пользовательского интерфейса. Возможно, наиболее важным из них является то, что код пользовательского интерфейса часто сложно тестировать неразрывно, особенно с помощью автоматических модульных тестов. Также существуют проблемы с качеством кода, которые могут повлиять на постоянную гибкость и ремонтопригодность вашего кода.
Если вы пойдете по пути наименьшего сопротивления, к которому вас ведут инструменты дизайна Visual Studio, вы можете в конечном итоге вложить слишком много кода в код позади.
Очень часто можно увидеть, как в программный код добавляется большое количество функций приложения.
Немногие разработчики действительно планируют помещать бизнес-логику в класс пользовательского интерфейса, но поскольку именно там Visual Studio помещает ваши обработчики событий, это становится слишком удобным местом для выполнения задач.
Широко признано, что программное обеспечение легче разрабатывать и поддерживать, если классы имеют четко определенные и разумно узкие обязанности.
Задача программного кода - напрямую взаимодействовать с объектами, составляющими пользовательский интерфейс, там, где это необходимо.
Как только вы начнете размещать код, который принимает решения о том, как ваше приложение ведет себя, там, что имеет тенденцию приводить к проблемам.
Логика приложения может не только перетекать в код, который, как предполагается, связан с пользовательским интерфейсом, некоторые разработчики начинают полагаться на элементы управления и другие объекты пользовательского интерфейса для хранения важного состояния приложения.
Модель просто хранит данные, представление просто хранит отформатированную дату, а контроллер (ViewModel) действует как связующее звено между ними. Контроллер может принимать входные данные из вида и размещать их на модели и наоборот.
Отдельная презентация
Чтобы избежать проблем, вызванных размещением логики приложения в коде или XAML, лучше всего использовать метод, известный как separated presentation. Имея XAML и код с минимумом, необходимым для работы с объектами пользовательского интерфейса напрямую, классы пользовательского интерфейса также содержат код для сложных взаимодействий, логики приложения и всего остального, как показано ниже слева.
Важные особенности раздельной презентации -
С разделенным представлением класс пользовательского интерфейса намного проще. Конечно, у него есть XAML, но код, стоящий за ним, делает настолько мало, насколько это практически возможно.
Логика приложения принадлежит к отдельному классу, который часто называют model.
Многие разработчики пытаются использовать привязку данных для подключения элементов XAML непосредственно к свойствам модели.
Проблема в том model полностью занимается вопросами того, что делает приложение, а не тем, как пользователь взаимодействует с приложением.
Большинство пользовательских интерфейсов имеют некоторое состояние, которое не принадлежит модели приложения. Например, если в вашем пользовательском интерфейсе используется перетаскивание, что-то должно отслеживать такие вещи, как, где сейчас находится перетаскиваемый элемент, как его внешний вид должен меняться, когда он перемещается над возможными целями перетаскивания, и как эти цели перетаскивания могут также изменяются при перетаскивании элемента над ними.
Такое состояние может быть на удивление сложным и требует тщательного тестирования.
На практике вам обычно нужен какой-то другой класс, расположенный между пользовательским интерфейсом и моделью. У этого есть две важные роли.
Во-первых, он адаптирует модель вашего приложения к конкретному представлению пользовательского интерфейса.
Во-вторых, здесь живет любая нетривиальная логика взаимодействия, и под этим я имею в виду код, необходимый для того, чтобы ваш пользовательский интерфейс вел себя так, как вы хотите.
Модель / представление / модель просмотра
View Modelявляется примером подхода раздельного представления, но давайте проясним, какие именно вещи у нас есть на каждом уровне. Есть три слоя -
- Model
- View
- ViewModel
Модель
Это classic объектная модель, состоящая из обычных классов C #, не имеющая прямого отношения к пользовательскому интерфейсу.
Обычно вы ожидаете, что коды вашей модели смогут компилироваться без ссылок на какие-либо библиотеки пользовательского интерфейса. Фактически, вы, вероятно, сможете взять тот же исходный код и скомпилировать его в приложение Silverlight, обычное консольное приложение .NET или даже веб-код на стороне сервера.
Типы в модели должны представлять концепции, с которыми работает ваше приложение.
Посмотреть
Представление обычно представляет собой UserControl, это может быть ваша главная страница или просто часть вашей страницы.
В большинстве приложений Silverlight рекомендуется разделить пользовательский интерфейс на небольшие части, определяющие UserControl или View для каждой части.
В этом отношении приложения Silverlight не уникальны. Что-то, что явно характерно для Silverlight, - это View. Чем более детализирован ваш пользовательский интерфейс, тем лучше. Мало того, что вы с меньшей вероятностью столкнетесь с другими разработчиками, работающими над теми же файлами, сохраняя небольшие и простые вещи, естественно, препятствует использованию ярлыков, которые приводят к спагетти-подобному коду.
Например, очень часто определяют View для представления отдельного элемента в списке.
ViewModel
Наконец, для каждого Viewвы пишете ViewModel. Итак, это одна из важных особенностейViewModel класс.
Он существует, чтобы обслуживать конкретное представление. ВViewModel специализируется на определенном способе представления вещей, таких как конкретный элемент данных, как он отображается в списках.
Вот почему это называется ViewModel; он адаптирует базовую модель специально для конкретного представления. Как и модель,ViewModelтакже является обычным классом C #. Необязательно быть производным от какого-либо определенного типа.
Как это бывает, некоторые разработчики считают удобным поместить некоторые общие функции в базовый класс ViewModel, но шаблон не требует этого. В частности, вашViewModelне является производным от какого-либо конкретного типа Silverlight. Однако, в отличие от модели, он может использовать типы Silverlight в своих свойствах.
Например, ваша ViewModel может сделать определенные части вашего пользовательского интерфейса видимыми только при определенных условиях, и поэтому вы можете предоставить свойство типа System.Windows.Visibility, которое элементы Silverlight используют для своего свойства Visibility. Это позволяет привязать видимость элемента, например панели, непосредственно к ViewModel.
пример
Давайте посмотрим на простой пример, в котором мы будем использовать Model-View-ViewModel (MVVM) подход.
Step 1 - Создайте новый проект приложения Silverlight. SilverlightMVVMDemo.
Step 2 - Добавьте три папки (Model, ViewModel и Views) в свой проект, как показано ниже.
Step 3 - Добавьте класс StudentModel в папку Model и вставьте в этот класс приведенный ниже код.
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));
}
}
}
}
Step 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;
}
}
}
Step 5 - Добавить Silverlight User Control щелкнув правой кнопкой мыши на Views папку и выберите Add New Item….
Step 6- Щелкните Добавить. Теперь вы увидите файл XAML. Добавьте следующий код в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>
Step 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>
Step 8 - Вот реализация Loaded событие в MainPage.xaml.cs файл, который обновит View из 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;
}
}
Step 9 - Когда приведенный выше код скомпилирован и выполнен, вы увидите следующий результат на своей веб-странице.
UI против ViewModel
Одна из самых сложных частей подхода MVVM - определить, где должна пройти разделительная линия. Не всегда очевидно, что и где принадлежит.
В частности, некоторые элементы пользовательского интерфейса предоставляют функциональные возможности, которые, согласно строгому представлению, вероятно, должны принадлежать модели представления.
В общем, не все варианты поведения реализованы в View так ViewModel дружелюбный.
Частично это связано с тем, что не существует стандартного способа упаковки поведения ViewModel для повторного использования, особенно если вы хотите использовать среду проектирования, такую как Visual Studio или Blend.
Преимущества MVVM
MVVM предлагает следующие преимущества -
Разделение проблем презентации (View, ViewModel, Model)
Чистый тестируемый и управляемый код. Может включать логику уровня представления в модульное тестирование.
Никакого кода позади кода, поэтому уровень представления и логика слабо связаны.
Лучший способ привязки данных.
Недостатки MVVM
Для простых пользовательских интерфейсов MVVM может оказаться излишним. Отладка будет немного сложной, когда у нас есть сложные привязки данных.