admin / 04.04.2018

Пример MVVM (Model-View-ViewModel) или программирование на WPF (Silverlight)

.

MVVM – Model – View – ViewModel – паттерн организации PL (presentation layer – уровень представления).

Паттерн MVVM применяется при создании приложений с помощью WPF и Silverlight.   Этот паттерн был придуман архитектором этих самых WPF и Silverlight — John Gossman (его блог). Паттерн MVVM применяется в Expression Blend.

Идеологически MVVM похож на Presentation Model описанный небезызвестным Фаулером, но MVVM сильно опирается на возможности WPF.

Основная особенность MVVM заключается в том, что все поведение выносится из представления (view) в  модель представления (view model).  Связывание представления и модели представления осуществляется декларативными байндингами в XAML разметке.

Паттерн MVVM. Часть 1.

Это позволяет тестировать все детали интерфейса не используя сложных инструментальных средств.

Я сначала хотел кратко описать применение MVVM и Unity для построения PL, но понял что одного поста для описания возможностей MVVM очень мало.

В WPF для передачи данных между объектами и визуальными элементами используются байндинги (binding – привязка) в простонародии биндинги. Передача может быть как однонаправленная, так и двунаправленная. Работают байндинги с помощью зависимых свойств (DependencyProperty) или интерфейса INotifyPropertyChanged. Передача управляющих воздействий от визуальных элементов осуществляется с помощью команд, реализующих интерфейс ICommand.

Для начала надоевший уже пример SayHello.

Как всегда используется супер-сложный класс бизнес логики:

public interface ISayHelloService { string SayHello(string name); } public class SayHelloSerivce : ISayHelloService { public string SayHello(string name) { return "Привет, " + name; } }

Теперь определение класса команды, которая состоит из пары делегатов

public class DelegateCommand : ICommand { Func<object, bool> _canExecute; Action<object> _execute; //Конструктор public DelegateCommand(Func<object, bool> canExecute, Action<object> execute) { this._canExecute = canExecute; this._execute = execute; } //Проверка доступности команды public bool CanExecute(object parameter) { return this._canExecute(parameter); } //Выполнение команды public void Execute(object parameter) { this._execute(parameter); } //Служебное событие public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested += value; } } }

Теперь напишем нашу модель представления.

public class ViewModel: INotifyPropertyChanged { //Имя public string Name { get; set; } //Текст приветствия public string HelloText { get; set; } //Команда public ICommand SayHelloCommand { get { return _sayHelloCommand; } } ISayHelloService _service; ICommand _sayHelloCommand; //Конструктор public ViewModel(ISayHelloService service) { this._service = service; //Создаем команду this._sayHelloCommand = new DelegateCommand( o => CanExecuteHello(), o => ExecuteHello()); } private void ExecuteHello() { this.HelloText = _service.SayHello(this.Name); OnPropertyChanged("HelloText"); } private bool CanExecuteHello() { return !string.IsNullOrEmpty(this.Name); } //Для поддержка байндинга #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } #endregion }

Получилось слегка многословно по причине того, что  пример искусственный.

Дело за разметкой:

<StackPanel> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="75" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <TextBlock Text="Введите имя"/> <TextBox Text="{Binding Name}" Grid.Column="1"/> </Grid> <TextBox Text="{Binding HelloText}"/> <Button Content="Сказать привет" Command="{Binding SayHelloCommand}"/> </StackPanel>

И немного изменим констрктор View:

public Window1(ViewModel model) { InitializeComponent(); DataContext = model; }

В App.xaml уберем атрибут StartupUri, и добавим обработчик события Startup, в котором напишем следующий код:

var container = new UnityContainer(); container .RegisterType<ViewModel>() .RegisterType<ISayHelloService, SayHelloSerivce>(); var window = container.Resolve<Window1>(); window.Show();

Можно нажать F5 и смотреть что получилось.

Теперь воспользуемся фичами WPF.

Изменим код ViewModel.

public class ViewModel : INotifyPropertyChanged { //Имя public string Name { get { return this._name; } set { this._name = value; OnPropertyChanged("Name"); OnPropertyChanged("HelloText"); } } //Текст приветствия public string HelloText { get { return _service.SayHello(this.Name); } } string _name; ISayHelloService _service; //Конструктор public ViewModel(ISayHelloService service) { this._service = service; } //Для поддержка байндинга #region INotifyPropertyChanged Members //Без изменений #endregion }

В разметке View уберем кнопку и поставим Mode=OneWay для байндинга второго текстбокса.

Кроме этого слега изменим App.xml.cs

var container = new UnityContainer(); container .RegisterType<ViewModel>(new ContainerControlledLifetimeManager()) .RegisterType<ISayHelloService, SayHelloSerivce>(); container.Resolve<Window1>().Show(); container.Resolve<Window1>().Show();

Два созданных окна будут разделять одну ViewModel и при вводе имени в одном из окон результат будет отображаться во всех.

Паттерн MVVM

Определение паттерна MVVM

Последнее обновление: 18.10.2016

Паттерн MVVM (Model-View-ViewModel) позволяет отделить логику приложения от визуальной части (представления). Данный паттерн является архитектурным, то есть он задает общую архитектуру приложения.

Данный паттерн был представлен Джоном Госсманом (John Gossman) в 2005 году как модификация шаблона Presentation Model и был первоначально нацелен на разработку приложений в WPF. И хотя сейчас данный паттерн вышел за пределы WPF и применяется в самых различных технологиях, в том числе при разработке под Android, iOS, тем не менее WPF является довольно показательной технологией, которая раскрывает возможности данного паттерна.

MVVM состоит из трех компонентов: модели (Model), модели представления (ViewModel) и представления (View).

Model

Модель описывает используемые в приложении данные. Модели могут содержать логику, непосредственно связанную этими данными, например, логику валидации свойств модели. В то же время модель не должна содержать никакой логики, связанной с отображением данных и взаимодействием с визуальными элементами управления.

Нередко модель реализует интерфейсы INotifyPropertyChanged или INotifyCollectionChanged, которые позволяют уведомлять систему об изменениях свойств модели. Благодаря этому облегчается привязка к представлению, хотя опять же прямое взаимодействие между моделью и представлением отсутствует.

View

View или представление определяет визуальный интерфейс, через который пользователь взаимодействует с приложением.

Как правильно написать на MVVM?

Применительно к WPF представление — это код в xaml, который определяет интерфейс в виде кнопок, текстовых полей и прочих визуальных элементов.

Хотя окно (класс Window) в WPF может содержать как интерфейс в xaml, так и привязанный к нему код C#, однако в идеале код C# не должен содержать какой-то логики, кроме разве что конструктора, который вызывает метод InitializeComponent и выполняет начальную инициализацию окна. Вся же основная логика приложения выносится в компонент ViewModel.

Однако иногда в файле связанного кода все может находиться некоторая логика, которую трудно реализовать в рамках паттерна MVVM во ViewModel.

Представление не обрабатывает события за редким исключением, а выполняет действия в основном посредством команд.

ViewModel

ViewModel или модель представления связывает модель и представление через механизм привязки данных. Если в модели изменяются значения свойств, при реализации моделью интерфейса INotifyPropertyChanged автоматически идет изменение отображаемых данных в представлении, хотя напрямую модель и представление не связаны.

ViewModel также содержит логику по получению данных из модели, которые потом передаются в представление. И также VewModel определяет логику по обновлению данных в модели.

Поскольку элементы представления, то есть визуальные компоненты типа кнопок, не используют события, то представление взаимодействует с ViewModel посредством команд.

Например, пользователь хочет сохранить введенные в текстовое поле данные. Он нажимает на кнопку и тем самым отправляет команду во ViewModel. А ViewModel уже получает переданные данные и в соответствии с ними обновляет модель.

Итогом применения паттерна MVVM является функциональное разделение приложения на три компонента, которые проще разрабатывать и тестировать, а также в дальнейшем модифицировать и поддерживать.

НазадСодержаниеВперед

.

FILED UNDER : IT

Submit a Comment

Must be required * marked fields.

:*
:*