Подпишись на наш Twitter

Быть в курсе появления новых статей!

Для тех из вас, кто только присоединился к серии уроков, мы узнали о том, как использовать Caliburn Micro для создания приложений WPF с архитектурой MVVM. Caliburn Micro является фрейморком используемым для построения .NET приложений (WPF, Silverlight и Windows Phone 7) используя некоторые популярные UI паттерны, включая MVVM, MVP и MVC. Он предоставляет много полезных способов уменьшить объем работы, которые вам нужно сделать для выполнения общих задач, таких как создание привязок данных и перехват событий. Различные особенности Caliburn Micro позволяют легко иметь чистую связь между объектами модели и пользовательского интерфейса. Это означает, что ваше приложение легко тестируется и поддерживается. Вот ссылки на предыдущие статьи в блоге:

В уроке на этой недели мы изучим, как использовать агрегатор событий, включенный в Caliburn Micro. Event aggregator является сервисом, который позволяет различным частям вашего приложения отправлять сообщений друг другу. Это полезно, когда ваше приложение сделано с использованием нескольких моделей представления, которым необходимо общаться между собой. Для этого вы подписываете объекты (такие как модели представления) на агрегатор событий и указываете тип сообщений, которые они должны слушать. Вы также определяете, что объект делает когда получает такие сообщения. Что когда другая часть приложений отправляет сообщений, то агрегатор событий проверяет, что соответствующие объекты его получили и выполнили необходимые действия. На протяжении этого урока мы будем расширять приложение, которое мы сделали в начале уроков. Вы можете скачать приложение здесь

Хотя агрегатор событий более полезен для больших приложений, которые имеют несколько моделей представления, мы по прежнему не будем усложнять приложение из нашего урока. Также помните, что данный урок имеет гораздо больше вещей для переваривания по сравнению с предыдущими! К концу этого урока, мы будем иметь приложение, которое отображает два изображения, каждое со своей собственной моделью представлений. Одно из представлений будет отображать некоторые радио-кнопки, каждая из которых представляет разные цвета. Когда радио кнопка нажата, мы опубликуем сообщение, содержащее соответствующий цвет. Второе представление будет слушать эти сообщения и изменить цвет прямоугольника. Мы будем делать это в 4-е этапа: Добавление еще одного вида в приложение, реализующие интерфейс IHandle<TMessage>, подпишем одну из моделей представления на агрегатор событий и наконец, публикация событий из другой модели представления.

Шаг 1: Добавление еще одного View и View-Model

Для того чтобы продемонстрировать агрегатор событий, нам нужны по крайней мере две модели представлений в нашем приложении. У нас уже есть одна (AppViewModel), так что давайте начнем с добавления другого. Помните о соглашении наименования описаном в уроке в начале? Добавьте новый класс ColorViewModel и UserControl с называнием ColorView. Также измените фон ColorView, что по крайней мере даст возможность на что посмотреть, когда мы добавили ее в приложение. С точки зрения визуальной структуры, у нас будет существующий AppView содержащий новые ColorView. (Представление не должно быть вложенным для того, чтобы использовать агрегатор событий; представление модели может прослушать сообщения, которые публикуется из любого места в приложении). Для этого в AppViewModel понадобится свойство типа ColorViewModel, которое мы установим в конструкторе следующим образом:

public class AppViewModel : PropertyChangedBase
{
  public AppViewModel(ColorViewModel colorModel)
  {
    ColorModel = colorModel;
  }
 
  public ColorViewModel ColorModel { get; private set; }
}

В AppView.xaml мы разделили грид на две колонки и отображаем ColorModelView в первой колонке. AppView.xaml теперь выглядит так:


  
    
    
  
  

Посмотрим, что же здесь должно произойти? Мы установили имя ContentControl таким же именем, что и свойство, которое мы добавили к AppViewModel. Исходя из этого, Caliburn Micro любезно привязал свойство Content у ContentControl к свойству ColorModel для нас. Когда мы запустим приложение позже, Caliburn Micro убедится, что экземпляр ColorView отображается для ColorViewModel.

Если бы мы были запустили приложение прямо сейчас, мы бы столкнулись об исключение, которое бы сообщило, что конструктор по умолчанию AppViewModel не может быть найден. Хм, это хороший момент: мы включили конструктор в AppViewModel, который требует в качестве параметра - объект ColorViewModel. Чтобы решить эту проблему, мы должны будем обновить наш AppBootstrapper как показано ниже. (Обязательно укажите ссылку на System.ComponentModel.Composition.dll в приложении).

using Caliburn.Micro;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
 
public class AppBootstrapper : Bootstrapper<AppViewModel>
{
  private CompositionContainer container;
 
  protected override void Configure()
  {
    container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
 
    CompositionBatch batch = new CompositionBatch();
 
    batch.AddExportedValue<IWindowManager>(new WindowManager());
    batch.AddExportedValue<IEventAggregator>(new EventAggregator());
    batch.AddExportedValue(container);
 
    container.Compose(batch);
  }
 
  protected override object GetInstance(Type serviceType, string key)
  {
    string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
    var exports = container.GetExportedValues<object>(contract);
 
    if (exports.Count() > 0)
    {
      return exports.First();
    }
 
    throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
  }
}

Это похоже на bootstrapper'ы использованные в примерах, которые идут с Caliburn Micro. Чтобы не делать эту статью слишком длинной, я не буду погружаться в детали того, что этот код делает (поиск по запросу MEF или Managed Extensibility Framework даст вам больше деталей, если они вам нужны).

Далее, мы должны включить атрибут Export в оба наших класса модели представления. Это необходимо для работы метода GetInstance в AppBootstrapper.

[Export(typeof(AppViewModel))]
public class AppViewModel : PropertyChangedBase
{
  ...
}
 
[Export(typeof(ColorViewModel))]
public class ColorViewModel
{
}

И, наконец, добавляем атрибут ImportingConstructor для конструктора AppViewModel. Это указывает, что этот конструктор должен использоваться, так как нет конструктора по умолчанию. Когда Caliburn Micro создаст AppViewModel, он также создаст экземпляр ColorViewModel для передачи в конструктор для нас.

[ImportingConstructor]
public AppViewModel(ColorViewModel colorModel)
{
  ColorModel = colorModel;
}

Теперь мы можем запустить приложение и видеть, что ColorView успешно отображается в AppView:

Давайте добавим прямоугольник во вторую колонку. Это будет прямоугольником, который изменяет цвет, когда сообщения обрабатываются, поэтому цвет будет контролироваться свойством из AppViewModel:

private SolidColorBrush _Color;
 
public SolidColorBrush Color
{
  get { return _Color; }
  set
  {
    _Color = value;
    NotifyOfPropertyChange(() => Color);
  }
}

Шаг 2: Реализация интерфейса IHandle<TMessage>

Мы собираемся публиковать сообщения от ColorViewModel, которые будут пойманы AppViewModel. Для этого нам нужно реализовать класс, который содержит информацию сообщения. Такой класс, как правило, очень маленький и простой. Он должен в основном обладать некоторыми свойствами, которые будут содержать информацию, которую мы хотим отправить. Вот класс сообщения, который мы собираемся использовать:

public class ColorEvent
{
  public ColorEvent(SolidColorBrush color)
  {
    Color = color;
  }
 
  public SolidColorBrush Color { get; private set; }
}

Для того, чтобы AppViewModel обработал соответствующие события, он должен реализовать интерфейс IHandle<TMessage>. В нашем случае, мы будем использовать ColorEvent как универсальный тип. Интерфейс IHandle имеет единственный метод, который нам необходимо реализовать под названием Handle. В методе Handle нашего AppViewModel, мы будем смотреть на SolidColorBrush отправленый в ColorEvent и использовать его для установки свойства Color. Это в свою очередь изменит цвет прямоугольника в представлении.

public void Handle(ColorEvent message)
{
  Color = message.Color;
}

Шаг 3: Подписка

Теперь мы должны подписать AppViewModel на агрегатор событий, что он начал прослушивать опубликованные сообщения. Мы сделаем это, добавив параметр в конструктор, типа IEventAggregator. Когда придет время для создания AppViewModel, Caliburn Micro передаст агрегатор событий, который мы создали в загрузчике (bootstrapper). Теперь в конструкторе, мы просто вызываем метод Subscribe:

[ImportingConstructor]
public AppViewModel(ColorViewModel colorModel, IEventAggregator events)
{
  ColorModel = colorModel;
 
  events.Subscribe(this);
}

Шаг 4: Публикация

В ColorViewModel также понадобится агрегатор событий для публикации сообщений. Добавьте конструктор в ColorViewModel, который принимает IEventAggregator и сохраняет его в поле. Не забудьте добавить атрибут ImportingConstructor:

private readonly IEventAggregator _events;
 
[ImportingConstructor]
public ColorViewModel(IEventAggregator events)
{
  _events = events;
}

Теперь нам нужно добавить радио кнопки в ColorView, обрабатывать щелчок на них и затем публиковать сообщение. Возможно, вы помните из из второго урока в этой серии о быстром способе прослушивать событие щелчка. Просто установите имя RadioButton быть таким же, как имя метода, который должен быть вызван. Мы могли бы, конечно, использовать параметры события вместо метода обработчика для каждой RadioButton, но я сделал это так, чтобы вы могли легко увидеть, что происходит:




public void Red()
{
  _events.Publish(new ColorEvent(new SolidColorBrush(Colors.Red)));
}
 
public void Green()
{
  _events.Publish(new ColorEvent(new SolidColorBrush(Colors.Green)));
}
 
public void Blue()
{
  _events.Publish(new ColorEvent(new SolidColorBrush(Colors.Blue)));
}

Вот и все. Запустите приложение и установите переключатель. Смотрите, что AppViewModel успешно получает сообщения от ColorViewModel для смены цвет прямоугольника.

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

Полный проект для Visual Studio 2010 этого урока можно загрузить отсюда. Надеюсь, вы найдете полезным агрегатор событий при организации связи между различными моделями представлений в вашем приложении. Ознакомьтесь с документацией для получения дополнительной информации в том числе, как сделать полиморфную подписку на события, кастомную публикацию и отписку от агрегатора событий.

В следующий раз мы рассмотрим Window Manager.

Увидимся в следующий раз.

Оригинал: Caliburn Micro Part 4: The Event Aggregator




Дата публикации: 01.02.2012 13:00

Ярлыки: Caliburn.Micro, Events, WPF