Перед прочтением необходимо почитать о шаблоне 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 – антипаттерн и бед от него намного больше чем пользы.