Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

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: }


Дата добавления: 2015-08-13; просмотров: 52 | Нарушение авторских прав


Читайте в этой же книге: Отсутствие метода OverrideMetadata() | Отсутствие свойства No PathSegment.IsStroked | Краткие итоги | Задача 3. | Принцип инверсии зависимостей | Формы инверсии зависимостей | IoC контейнер | Сопоставление модели представления и представления | Реализация INotifyPropertyChanged средствами аспектно-ориентированного программирования | Краткие итоги |
<== предыдущая страница | следующая страница ==>
Понятие IChildViewModelManager| Реализация ChildViewModelBase

mybiblioteka.su - 2015-2024 год. (0.014 сек.)