- •Разделы дисциплины и виды занятий в часах
- •Общая информация о курсе
- •Введение
- •Об авторах
- •Лекция 1. Краткое знакомство с моделью программирования xaml.
- •Краткий экскурс в историю графических интерфейсов пользователя
- •Windows Presentation Foundation – три в одном
- •Декларативное программирование ui и xaml
- •Основы модели ui и xaml
- •Элементы xaml
- •Элементы управления
- •Графические примитивы
- •Службы документов
- •Преобразования и анимация
- •Ресурсы и стили
- •Разделение труда дизайнера и разработчика
- •Xaml – текущая поддержка
- •Модель программирования xaml
- •Ключевые термины
- •Краткие итоги
- •Xaml подчиняется всем правилам wellformed xml, в частности это означает, что xaml документ:
- •Вариант 2 Задачи 3.
- •Вариант 2 Задачи 8.
- •Вариант 3 Задачи 8.
- •Xaml может использоваться для описания ui:
- •Xaml может использоваться:
- •Лабораторная работа 1. Размещение элементов управления.
- •Задания для самостоятельного выполнения
- •Учебный элемент. Создание нового проекта для Silverlight в VisualStudio 2010.
- •Шаг 1. Создание проекта
- •Шаг 2. Добавляем элементы интерфейса для xaml-страниц
- •Учебный элемент. Silverlight: размещение элементов.
- •Шаг 1. Принципы разметки
- •Шаг 2. Создаем Twitter-приложение
- •Шаг 3. Навигация
- •Шаг 4. Размещаем элементы для страницы поиска
- •Шаг 5. Изменяем UriMapper для Search.Xaml
- •Краткие итоги
- •Литература
- •Лекция 2. Сведения о wpf и Silverlight: Введение и архитектура платформ.
- •Независимость от разрешения
- •Архитектура Silverlight
- •Состав ядра представления:
- •В подмножество .Net Framework входят:
- •Архитектура wpf
- •Иерархия классов
- •Элементы управления wpf
- •Компоновочные элементы управления в системе wpf
- •Ключевые термины
- •Краткие итоги
- •Лекция 3. Стили и шаблоны элементов управления wpf.
- •Создание стиля
- •Использование стиля
- •Размещение стилей
- •Основы шаблонов
- •Создание шаблона
- •Повторное использование шаблона Control’а
- •Связывание в Шаблонах
- •Установка шаблонов через стили
- •Повторное использование настроек цвета
- •Ключевые термины
- •Краткие итоги
- •Вариант 2 Задачи 5.
- •Задания для самостоятельного выполнения
- •Учебный элемент. Стили и ресурсы в wpf
- •Шаг 1. Применение стиля в xaml документе
- •Шаг 2. Динамическое применение стилей в коде приложения
- •Поддержка множества целевых платформ
- •Клиентский профиль .Net
- •Визуальный конструктор Visual Studio
- •Графика Шейдеры
- •Кеширование графики
- •Новые функции для анимации
- •Усовершенствования двухмерной графики.
- •Поддержка Generics
- •Ключевые термины
- •Краткие итоги
- •Набор для практики
- •Литература
- •Лекция 5. Silverlight и wpf в Visual Studio 2010 (продолжение).
- •Новые возможности Silverlight 4. Silverlight 5: основные нововведения ожидаемого релиза. Хронология Silverlight
- •Связывание с данными Отладка
- •Поддержка Full-Trust внутри браузера
- •Обработка множественного нажатия кнопки мыши
- •Поддержка выбора элементов в ItemsControl с клавиатуры
- •Повышение полномочий для приложений в браузере
- •Поддержка нескольких окон
- •Доступ к файловой системе для приложений с повышенными привилегиями
- •Установка имени файла по умолчанию в SaveFileDialog
- •Улучшение работы с аудио
- •Изменение скорости проигрывания медиа
- •Поддержка пульта дистанционного управления
- •Работа с текстом
- •Отладка при связывании с данными
- •Улучшенная поддержка шаблона mvvm
- •Использование связывания в стилях
- •Неявные шаблоны
- •Другие изменения
- •Краткие итоги
- •Вариант 2 Задачи 2.
- •Вариант 2 Задачи 4.
- •Вариант 2 Задачи 6.
- •Вариант 3 Задачи 6.
- •Литература
- •Лекция 6. Привязка данных в технологиях wpf и Silverlight
- •Принципы работы с данными
- •Модель данных в .Net
- •Всепроникающее связывание
- •Преобразование данных
- •Ресурсы
- •Основные принципы связывания
- •Привязка к объектам clr
- •Редактирование
- •Ключевые термины
- •Вариант 2 Задачи 5.
- •Шаг 1. Создание повторно используемой функциональности
- •Устанавливаем стили для элементов управления
- •Двусторонняя привязка данных
- •Шаг 2. Добавление обработки событий клавиатуры
- •Шаг 3. Инкапсуляция разметки и логики в элемент управления UserControl
- •Реализация элемента управления
- •Добавление кода
- •Использование пользовательского элемента управления
- •Многократное использование
- •Шаг 1. Рефакторинг кода адресной формы
- •Код внутри класса AdressCustomControl
- •Определение свойств зависимости
- •Шаг 2. Рефакторинг кода разметки указателя цвета
- •Шаг 3. Оптимизация шаблона элемента управления
- •Манипулирование частями шаблона
- •Документирование частей шаблона
- •Ключевые термины
- •Вариант 2 Задачи 3.
- •Вариант 3 Задачи 3.
- •Задача 4. Вариант 1 Задачи 4.
- •Вариант 2 Задачи 4.
- •Вариант 3 Задачи 4.
- •Задача 5. Вариант 1 Задачи 5.
- •Вариант 2 Задачи 5.
- •Вариант 3 Задачи 5.
- •Задача 6. Вариант 1 Задачи 6.
- •Вариант 2 Задачи 6.
- •Вариант 3 Задачи 6.
- •Задача 7. Вариант 1 Задачи 7.
- •Вариант 2 Задачи 7.
- •Вариант 3 Задачи 7.
- •Литература
- •Лабораторная работа 3. Пользовательские элементы управления.
- •Задания для самостоятельного выполнения
- •Учебный элемент. Создание пользовательского элемента управления средствами дизайнера VisualStudio Шаг 1. Создание Silverlight проекта
- •Шаг 2. Создание пользовательского элемента управления
- •Шаг 5. Использование Custom Control
- •Учебный элемент. Создание пользовательского элемента управления средствами дизайнера Expression Blend
- •Шаг 1. Инкапсуляция ui в User Control
- •Шаг 2. Привязка адресов к нашему AddressUserControl – контроллеру.
- •Краткие итоги
- •Литература
- •Лекция 8. Использование событий, команд и триггеров в технологиях wpf и Silverlight
- •Принципиальные основы действий
- •Композиция элементов
- •Слабая связь
- •Декларативные действия
- •События
- •Команды
- •Команды и привязка к данным
- •Триггеры
- •Добавление триггеров к данным
- •Добавление триггеров к элементам управления
- •Вариант 2 Задачи 2.
- •Вариант 2 Задачи 6.
- •Вариант 2 Задачи 8.
- •Вариант 3 Задачи 8.
- •Литература
- •Лабораторная работа 4. Использование команд в технологиях wpf и Silverlight
- •Задания для самостоятельного выполнения
- •Учебный элемент. Использование стандартных и нестандартных команд Шаг 1. Использование стандартных команд.
- •Шаг 2. Использование нестандартных команд.
- •Шаг 3. Перевод команд из неактивного состояния в активное и обратно.
- •Краткие итоги
- •Литература
- •Лекция 9. Применение паттерна mvvm как оптимального при проектировании wpf и Silverlight приложений
- •Паттерн Model-View-ViewModel (mvvm)
- •Обязанности и характеристики классов.
- •Класс представления (View).
- •Класс модели представления (View Model).
- •Представление или Модель Представления?
- •Класс модели (Model).
- •Взаимодействие классов.
- •Привязка данных.
- •Реализация iNotifyPropertyChanged.
- •Реализация iNotifyCollectionChanged.
- •Реализация iCollectionView.
- •Команды.
- •Реализация Command Objects.
- •Подтверждение правильности данных и сообщение об ошибках.
- •Реализация iDataErrorInfo.
- •Создание и соединение.
- •Создание модели представления через xaml.
- •Создание модели представления программно.
- •Создание представления, определенного как шаблон данных.
- •Вариант 2 Задачи 1.
- •Вариант 3 Задачи 1.
- •Задача 2. Вариант 1 Задачи 2.
- •Вариант 2 Задачи 2.
- •Вариант 3 Задачи 2.
- •Задача 3. Вариант 1 Задачи 3.
- •Вариант 2 Задачи 3.
- •Вариант 2 Задачи 6.
- •Вариант 3 Задачи 6.
- •Задача 7. Вариант 1 Задачи 7.
- •Вариант 2 Задачи 7.
- •Вариант 3 Задачи 7.
- •Литература
- •Лабораторная работа 5. Реализация wpf проекта с помощью mvvm toolkit’а
- •Задания для самостоятельного выполнения
- •Учебный элемент. Реализация паттерна mvvm средствами Model-View-ViewModel Toolkit 0.1
- •Шаг 1. Постановка задачи
- •Шаг 4. Редактирование
- •Шаг 5. Команды
- •Краткие итоги
- •Литература
- •Лекция 10. Проектирование приложения с учетом использования единого опыта разработки для настольных и Web-проектов.
- •Подходы к решению задачи
- •Разработка кроссплатформенного проекта с самого начала
- •Разработка для одной платформы с последующим портированием на другую
- •Инструментарий
- •Создание ссылок на файлы в Visual Studio
- •Создание ссылок на xaml файлы
- •Директивы препроцессора
- •Разделяемые классы
- •Синхронное использование xaml
- •Решение проблем недостающего функционала Отсутствие FrameworkPropertyMetadata
- •Отсутствие приведения значения
- •Отсутствие метода OverrideMetadata()
- •Отсутствие зависимых свойств только для чтения
- •Отсутствие класса Brushes
- •Конструкторы по умолчанию для геометрий
- •Отсутствие свойства No PathSegment.IsStroked
- •Краткие итоги
- •Принцип инверсии зависимостей
- •Формы инверсии зависимостей
- •IoC контейнер
- •Определение моделей представления
- •Определение представлений
- •Сопоставление модели представления и представления
- •Реализация iNotifyPropertyChanged средствами аспектно-ориентированного программирования
- •Краткие итоги
- •IoC контейнер в mef инкапсулируется классом …
- •Понятие iChildViewModelManager
- •Реализация ChildViewModelBase
- •Реализация ModalChildViewModelBase
- •Реализация MessageViewModel
- •Краткие итоги
- •Литература Лабораторная работа 6. Построение кроссплатформенного Silverlight/wpf приложения.
- •Создание проектов
- •Краткие итоги
- •Список литературы
Понятие iChildViewModelManager
Очевидно, что модели представления дочерних окон не могут работать сами по себе, и необходим механизм, отображающий их в настоящие дочерние окна целевой платформы (Silverlight или WPF).
Для этих целей необходимо ввести менеджер дочерних моделей представления: он ведет учет видимых в настоящий момент моделей представления и сообщает о них всем внешним слушателям, подписанным на изменения коллекции ViewModels:
1: /// <summary>
2: /// Interface of class managing closeable View Models of
3: /// the specified type
4: /// </summary>
5: public interface IChildViewModelManager
6: : ICloseableViewModelPresenter<IChildViewModel>
7: {
8: /// <summary>
9: /// Collection of managed View Models
10: /// </summary>
11: ReadOnlyObservableCollection<IChildViewModel>
12: ViewModels { get; }
13: }
Здесь используется понятие презентера закрываемой модели представления, который принимает к регистрации видимые модели представления:
1: /// <summary>
2: /// Interface of closeable View Model presenter
3: /// </summary>
4: [InheritedExport]
5: public interface ICloseableViewModelPresenter<in TViewModelBase>
6: where TViewModelBase : ICloseableViewModel
7: {
8: /// <summary>
9: /// Shows <paramref name="viewModel" />
10: /// </summary>
11: void ShowViewModel(TViewModelBase viewModel);
12: }
Реализация менеджера дочерних моделей представления принимает к регистрации видимые модели представления дочерних окон и добавляет их во внутреннюю коллекцию. Одновременно с регистрацией происходит привязка к событию Closed модели представления, по которому она снимается с регистрации в менеджере и удаляется из коллекции:
1: /// <summary>
2: /// Manages closeable View Models of the specified type
3: /// </summary>
4: internal class ChildViewModelManager
5: : IChildViewModelManager
6: {
7: // Private fields
8: private readonly ObservableCollection<IChildViewModel>
9: _viewModelsInternal =
10: new DispatchObservableCollection<IChildViewModel>();
11: private ReadOnlyObservableCollection<IChildViewModel>
12: _viewModels;
13:
14: /// <summary>
15: /// Collection of managed View Models
16: /// </summary>
17: public ReadOnlyObservableCollection<IChildViewModel>
18: ViewModels
19: {
20: get
21: {
22: return _viewModels ?? (_viewModels =
23: new ReadOnlyObservableCollection<IChildViewModel>(
24: _viewModelsInternal));
25: }
26: }
27:
28: #region ICloseableViewModelPresenter<TViewModelBase> Members
29:
30: void ICloseableViewModelPresenter<IChildViewModel>
31: .ShowViewModel(IChildViewModel viewModel)
32: {
33: ShowViewModelCore(viewModel);
34: }
35:
36: #endregion
37:
38: /// <summary>
39: /// Closes <paramref name="viewModel" />
40: /// </summary>
41: protected virtual void CloseViewModelCore
42: (IChildViewModel viewModel)
43: {
44: viewModel.Closed -= OnViewModelClosed;
45:
46: Debug.Assert(_viewModelsInternal.Contains(viewModel));
47: _viewModelsInternal.Remove(viewModel);
48: }
49:
50: /// <summary>
51: /// Shows <paramref name="viewModel" />,
52: /// adding it to collection
53: /// </summary>
54: protected virtual void ShowViewModelCore
55: (IChildViewModel viewModel)
56: {
57: Debug.Assert(!viewModel.IsClosed);
58: viewModel.Closed += OnViewModelClosed;
59:
60: Debug.Assert(!_viewModelsInternal.Contains(viewModel));
61: _viewModelsInternal.Add(viewModel);
62: }
63:
64: private void OnViewModelClosed(object sender, EventArgs e)
65: {
66: Debug.Assert(sender is IChildViewModel);
67: CloseViewModelCore((IChildViewModel)sender);
68: }
69: }
ChildViewManager
Теперь, когда IChildViewModelManager ведет учет моделей представления дочерних окон, можно перейти к следующему понятию – менеджеру дочерних представлений. Он прослушивает коллекцию ViewModel на предмет изменения по событию CollectionChanged интерфейса INotifyCollectionChanged: если в коллекцию добавлена новая модель представления, то необходимо создать для неё дочернее окно и сохранить соответствие в словаре; затем, при удалении модели представления из коллекции достаточно найти дочернее окно по словарю, закрыть его и удалить запись о соответствии.
Следует заметить, что так как объекты пользовательского интерфейса как правило не позволяют взаимодействовать с собой из потока, отличного от GUI потока, а вызовы слоя моделей представления могут происходить в любом контексте, в том числе в потоке из пула потоков (наиболее часто в нем выполняются обратные методы вызова асинхронных операций Windows Communication Foundation сервисов), то необходимо явно отправлять события изменений коллекции ViewModels на Dispatcher GUI потока посредством DispatcherSynchronizationContext.
1: #if SILVERLIGHT
2: using ChildViewType = System.Windows.Controls.ChildWindow;
3: #else
4: using ChildViewType = System.Windows.Window;
5: #endif
6:
7: public class ChildViewManager
8: {
9: [ImportingConstructor]
10: public ChildViewManager
11: (IEnumerable<IChildViewModel> viewModelCollection)
12: {
13: OnViewModelCollectionChanged(viewModelCollection,
14: new NotifyCollectionChangedEventArgs
15: (NotifyCollectionChangedAction.Reset));
16:
17: var notifiable = viewModelCollection
18: as INotifyCollectionChanged;
19:
20: if (notifiable != null)
21: {
22: notifiable.CollectionChanged += (sender, e)
23: => DispatcherSynchronizationContext.Post(arg =>
24: OnViewModelCollectionChanged(sender, e), null);
25: }
26: }
27:
28: // Private readonly fields
29: protected static readonly DispatcherSynchronizationContext
30: DispatcherSynchronizationContext =
31: new DispatcherSynchronizationContext(
32: #if SILVERLIGHT
33: Deployment.Current.Dispatcher
34: #else
35: Application.Current.Dispatcher
36: #endif
37: );
38:
39: // Private fields
40: private readonly IDictionary<IChildViewModel, ChildViewType>
41: _childViews =
42: new Dictionary<IChildViewModel, ChildViewType>();
43:
44: /// <summary>
45: /// Closes all managed <see cref="ChildViewPresenter" />
46: /// </summary>
47: protected virtual void CloseAllViews()
48: {
49: foreach (KeyValuePair<IChildViewModel, ChildViewType>
50: pair in _childViews)
51: {
52: CloseView(pair.Key);
53: }
54: }
55:
56: /// <summary>
57: /// Closes specified <see cref="ChildViewPresenter" />
58: /// </summary>
59: protected virtual void CloseView
60: (IChildViewModel childViewModel)
61: {
62: Debug.Assert(_childViews.ContainsKey(childViewModel));
63:
64: ChildViewType childView = _childViews[childViewModel];
65: _childViews.Remove(childViewModel);
66: childView.Close();
67: }
68:
69: /// <summary>
70: /// Shows specified <see cref="ChildViewPresenter" />
71: /// </summary>
72: protected virtual void ShowView
73: (IChildViewModel childViewModel)
74: {
75: ChildViewType childWindow = new ChildViewPresenter
76: { DataContext = childViewModel };
77: _childViews.Add(childViewModel, childWindow);
78: childWindow.Show();
79: }
80:
81: private void OnViewModelCollectionChanged(object sender,
82: NotifyCollectionChangedEventArgs e)
83: {
84: switch (e.Action)
85: {
86: case NotifyCollectionChangedAction.Add:
87: foreach (IChildViewModel viewModel in e.NewItems)
88: {
89: ShowView(viewModel);
90: }
91: break;
92:
93: case NotifyCollectionChangedAction.Remove:
94: foreach (IChildViewModel viewModel in e.OldItems)
95: {
96: CloseView(viewModel);
97: }
98: break;
99:
100: case NotifyCollectionChangedAction.Reset:
101: CloseAllViews();
102:
103: foreach (IChildViewModel viewModel
104: in (IEnumerable)sender)
105: {
106: ShowView(viewModel);
107: }
108: break;
109:
110: default:
111: throw new ArgumentOutOfRangeException
112: ("e.Action is out of range", (Exception)null);
113: }
114: }
115: }
ChildViewPresenter – это окно Window в случае WPF и ChildWindow в случае Silverlight. Данные элементы управления содержат в себе ViewModelPresenter, который уже в свою очередь определяет, какое представление необходимо отобразить в дочернем окне.
Дополнительной обработки требует случай закрытия дочернего окна через нажатие на иконку в верхнем правом углу. Реализованная логика менеджеров поддерживает корректную инициацию закрытия дочернего окна исключительно со слоя представления, поэтому закрытие одного только ChildViewPresenter не приведет к срабатыванию логики закрытия модели представления.
Для правильной работы приложения при попытке пользователя закрыть дочернее окно системными средствами необходимо отменить это закрытие в событии OnClosing и инициировать корректное закрытие модели представления, которое в свою очередь затем приведет к закрытию окна. С точки зрения пользователя поведение приложения будет корректным, и при этом архитектура приложения не будет загрязнена дополнительной логикой обработки специального случая.
Реализация ChildViewPresenter для WPF:
1: <Window x:Class="TestProject.ChildViewPresenter"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:viewModelMapping="clr-namespace:TestProject"
5: SizeToContent="WidthAndHeight"
6: Title="{Binding Title}"
7: WindowStartupLocation="CenterScreen">
8:
9: <viewModelMapping:ViewModelPresenter
10: x:Name="ViewModelPresenter" ViewModel="{Binding}" />
11: </Window>
Для Silverlight:
1: <controls:ChildWindow x:Class="TestProject.ChildViewPresenter"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:controls=
5: "http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
6: xmlns:ViewModelMapping="clr-namespace:TestProject"
7: Title="{Binding Title}">
8:
9: <ViewModelMapping:ViewModelPresenter ViewModel="{Binding}" />
10: </controls:ChildWindow>
Код данных элементов управления одинаковый как в Silverlight, так и в WPF:
1: public partial class ChildViewPresenter
2: {
3: /// <summary>
4: /// Initializes a new instance
5: /// </summary>
6: public ChildViewPresenter()
7: {
8: InitializeComponent();
9: }
10:
11: /// <summary>
12: /// Underlying View Model
13: /// </summary>
14: private ICloseableViewModel ViewModel
15: {
16: get
17: {
18: Debug.Assert(DataContext == null
19: || DataContext is ICloseableViewModel);
20: return (ICloseableViewModel)DataContext;
21: }
22: }
23:
24: /// <summary>
25: /// Processes window closing
26: /// </summary>
27: protected override void OnClosing(CancelEventArgs e)
28: {
29: base.OnClosing(e);
30:
31: Debug.Assert(ViewModel != null);
32:
33: if (!ViewModel.IsClosed)
34: {
35: e.Cancel = true;
36: ViewModel.Close();
37: }
38: }
39: }
