Перед прочтением необходимо почитать о шаблоне EventAggregator. EventAggregator обеспечивает взаимодействие компонент и сервисов составного приложения, через слабую связанность.
EventAggregator можно найти во многих WPF-каркасах: Mvvm Light -класс Messenger, Catel – класс MessageMediator. Я познакомился с EventAggregator вместе с WPF каркасом Prism. Использование EventAggregator оказалось простым и гибким. Компоненты системы становятся независимыми друг от друга – изменяя один компонент, я не боюсь сломать другой.
При рассмотрении отдельных компонент все так и есть, но поднявшись на уровень работы компонентов в системе, можно разглядеть серьёзные проблемы:

Делюсь моим взглядом на слишком слабую связанность и не явное взаимодействие между частями системы.
Для управления светодиодами понадобятся: кнопка питания – Power, переключатель с двумя состояниями – Switch и два светодиода – RedLed и BlueLed. На WPF это выглядит, как то так:

Кнопка Power зажигает один из светодиодов в зависимости от состояния переключателя Switch.
В системе основанной на EventAggregator выделим два события: включения/выключения питания — PowerEvent и изменение состояния переключателя — SwitchEvent.
Событие PowerEvent публикуется при нажатии на кнопку Power, событие SwitchEvent публикуется при нажатии на Switch. Светодиоды подписываются на события PowerEvent и SwitchEvent.
Светодиод зажигается, если есть питание и переключатель находится в нужном состоянии.
Все работает отлично!
В схеме всего 4 компонента, но что нужно сделать, что бы светодиод заменить на другой элемент? Скопипастить подписку из LedViewModel – продублировать.
При динамической замене компонент, все еще хуже, везде нужно будет дублировать отписку. EventAggregator по умолчанию создает weakreference. С Weakreference отписка должна проходить автоматически, но при динамической замене компонент, неизвестно когда будет удалена подписка — везде нужно будет дублировать явную отписку.
Заменив компонент, я не знаю в каком состоянии система: включено ли питание, в каком положении Switch, мне просто не откуда это взять. Одно из решений – ввести в систему вспомогательное событие. Вспомогательное событие будет просить компоненты опубликовать свои события – PowerEvent и SwitchEvent. Теперь везде нужно позаботиться о публикации и подписке на это событие – система распадается и превращается в паутину.
Компоненты системы знают только об EventAggregator, но означает ли это слабую связанность? Нет. Несмотря на изолированность компонент друг от друга, в системе присутствует очень сильная неявная связь. Сильная связь выражена в наборе событий, которые нужно обрабатывать. Я не могу заменить Switch на другой компонент, не доработав Led. В результате связь между частями системы превращается в узел: сильная, не явная и запутанная.
Про использование EventAggregator внутри сервисов, которые реализуют некоторый интерфейс и подменяются в зависимости от конфигурации… Лучше не вспоминать.
Использование EventAggregator нарушает 3 из 5 принципов SOLID. Единственность ответственности – подписка/отписка не забота компонентов схемы. Открытость закрытость – при изменении схемы взаимодействия компонентов, нужно править подписку/отписку. Инверсия зависимости – компонент сам решает, на какие события подписываться/отписываться.
3 из 5, а проблем…
P.S. используйте EventAggregator с осторожностью. Для меня EventAggregator – антипаттерн и бед от него намного больше чем пользы.
EventAggregator можно найти во многих WPF-каркасах: Mvvm Light -класс Messenger, Catel – класс MessageMediator. Я познакомился с EventAggregator вместе с WPF каркасом Prism. Использование EventAggregator оказалось простым и гибким. Компоненты системы становятся независимыми друг от друга – изменяя один компонент, я не боюсь сломать другой.
При рассмотрении отдельных компонент все так и есть, но поднявшись на уровень работы компонентов в системе, можно разглядеть серьёзные проблемы:

Делюсь моим взглядом на слишком слабую связанность и не явное взаимодействие между частями системы.
Управление светодиодами через EventAggregator
Для управления светодиодами понадобятся: кнопка питания – Power, переключатель с двумя состояниями – Switch и два светодиода – RedLed и BlueLed. На WPF это выглядит, как то так:

Кнопка Power зажигает один из светодиодов в зависимости от состояния переключателя Switch.
В системе основанной на EventAggregator выделим два события: включения/выключения питания — PowerEvent и изменение состояния переключателя — SwitchEvent.
Событие PowerEvent публикуется при нажатии на кнопку Power, событие SwitchEvent публикуется при нажатии на Switch. Светодиоды подписываются на события PowerEvent и SwitchEvent.
Светодиод зажигается, если есть питание и переключатель находится в нужном состоянии.
Код событий
enum Power { On = 1, Off = 0, } class PowerEvent : PubSubEvent<Power> { } public enum SwitchConnection { Connection1, Connection2, } class SwitchEvent : PubSubEvent<SwitchConnection> { }
Код управления питанием
public class PowerViewModel : BindableBase { readonly IEventAggregator _aggregator; bool _power; public PowerViewModel(IEventAggregator aggregator) { _aggregator = aggregator; } public bool Power { get { return _power; } set { if (SetProperty(ref _power, value)) _aggregator.GetEvent<PowerEvent>().Publish(_power ? Events.Power.On : Events.Power.Off); } } }
Код управления переключателем
public class SwitchViewModel : BindableBase { readonly IEventAggregator _aggregator; bool _switch; public SwitchViewModel(IEventAggregator aggregator) { _aggregator = aggregator; Switch = true; } public bool Switch { get { return _switch; } set { if (SetProperty(ref _switch, value)) _aggregator.GetEvent<SwitchEvent>().Publish(_switch ? SwitchConnection.Connection1 : SwitchConnection.Connection2); } } }
Код светодиода
/// <summary> /// ViewModel светодиода. /// </summary> public class LedViewModel : BindableBase { readonly SwitchConnection _activeConnection; readonly Brush _activeLight; Power _currentPower; SwitchConnection _currentConnection; Brush _currentlight; public LedViewModel(SwitchConnection connection, Brush light, IEventAggregator aggregator) { _activeConnection = connection; _activeLight = light; aggregator.GetEvent<PowerEvent>().Subscribe(OnPowerChanged); aggregator.GetEvent<SwitchEvent>().Subscribe(OnSwitch); Update(); } /// <summary> /// Свет от светодиода. /// </summary> public Brush Light { get { return _currentlight; } private set { SetProperty(ref _currentlight, value); } } /// <summary> /// Обработчик переключателя. /// </summary> void OnSwitch(SwitchConnection connection) { if (SetProperty(ref _currentConnection, connection)) Update(); } /// <summary> /// Обработчик питания. /// </summary> void OnPowerChanged(Power power) { if (SetProperty(ref _currentPower, power)) Update(); } void Update() { Brush currentLight = Brushes.Transparent; switch (_currentPower) { case Power.On: if (_currentConnection == _activeConnection) currentLight = _activeLight; break; case Power.Off: break; default: throw new ArgumentOutOfRangeException(); } Light = currentLight; } }
Xaml разметка
<Window x:Class="AggregatorAntiPattern.MainWindow" 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:local="clr-namespace:AggregatorAntiPattern" mc:Ignorable="d" Height="350" Width="525"> <Window.Resources> <Style TargetType="Path" x:Key="Light"> <Setter Property="Stroke" Value="Black" /> <Setter Property="StrokeThickness" Value="2" /> <Setter Property="Fill" Value="{Binding Light}" /> <Setter Property="Data"> <Setter.Value> <EllipseGeometry RadiusX="10" RadiusY="10" /> </Setter.Value> </Setter> </Style> <Style TargetType="Line" x:Key="Connection"> <Setter Property="Stroke" Value="Black" /> <Setter Property="StrokeThickness" Value="1" /> </Style> </Window.Resources> <Canvas Margin="20"> <ToggleButton Canvas.Top="120" Content=" Power " DataContext="{Binding PowerVM}" IsChecked="{Binding Power}" /> <Line Canvas.Top="130" Canvas.Left="40" X1="0" X2="90" Y1="0" Y2="0" Style="{StaticResource Connection}" /> <ToggleButton Canvas.Top="120" Canvas.Left="120" Content=" Switch " DataContext="{Binding SwitchVM}" IsChecked="{Binding Switch}" /> <Line Canvas.Top="130" Canvas.Left="165" X1="0" X2="77" Y1="0" Y2="-30" Style="{StaticResource Connection}" /> <Line Canvas.Top="130" Canvas.Left="165" X1="0" X2="77" Y1="0" Y2="30" Style="{StaticResource Connection}" /> <Path Canvas.Top="100" Canvas.Left="250" DataContext="{Binding Connection1Light}" Style="{StaticResource Light}" /> <Path Canvas.Top="160" Canvas.Left="250" DataContext="{Binding Connection2Light}" Style="{StaticResource Light}" /> </Canvas> </Window>
Связующий код
var aggregator = new EventAggregator(); PowerVM = new PowerViewModel(aggregator); SwitchVM = new SwitchViewModel(aggregator); Connection1Light = new LedViewModel(SwitchConnection.Connection1, Brushes.Red, aggregator); Connection2Light = new LedViewModel(SwitchConnection.Connection2, Brushes.Blue, aggregator);
Все работает отлично!
Проблемы с EventAggregator
В схеме всего 4 компонента, но что нужно сделать, что бы светодиод заменить на другой элемент? Скопипастить подписку из LedViewModel – продублировать.
При динамической замене компонент, все еще хуже, везде нужно будет дублировать отписку. EventAggregator по умолчанию создает weakreference. С Weakreference отписка должна проходить автоматически, но при динамической замене компонент, неизвестно когда будет удалена подписка — везде нужно будет дублировать явную отписку.
Заменив компонент, я не знаю в каком состоянии система: включено ли питание, в каком положении Switch, мне просто не откуда это взять. Одно из решений – ввести в систему вспомогательное событие. Вспомогательное событие будет просить компоненты опубликовать свои события – PowerEvent и SwitchEvent. Теперь везде нужно позаботиться о публикации и подписке на это событие – система распадается и превращается в паутину.
Компоненты системы знают только об EventAggregator, но означает ли это слабую связанность? Нет. Несмотря на изолированность компонент друг от друга, в системе присутствует очень сильная неявная связь. Сильная связь выражена в наборе событий, которые нужно обрабатывать. Я не могу заменить Switch на другой компонент, не доработав Led. В результате связь между частями системы превращается в узел: сильная, не явная и запутанная.
Что нужно сделать, что бы в схеме было несколько Switch?
Прежде чем получить ответ, хорошо подумйте.

Про использование EventAggregator внутри сервисов, которые реализуют некоторый интерфейс и подменяются в зависимости от конфигурации… Лучше не вспоминать.
Откуда ростут проблемы
Использование EventAggregator нарушает 3 из 5 принципов SOLID. Единственность ответственности – подписка/отписка не забота компонентов схемы. Открытость закрытость – при изменении схемы взаимодействия компонентов, нужно править подписку/отписку. Инверсия зависимости – компонент сам решает, на какие события подписываться/отписываться.
3 из 5, а проблем…
P.S. используйте EventAggregator с осторожностью. Для меня EventAggregator – антипаттерн и бед от него намного больше чем пользы.