caliburn.micro eventAggregator: Обработка сообщения в Screen Collection
У меня есть следующий код в моем калибровочном микро-приложении. Я использую eventAggregator для отправки сообщений из одной модели представления в другую.
Рассмотрим следующий код:
public class ShellViewModel : Conductor<IWorkspace>.Collection.OneActive, IShell
{
...
}
public class ViewModelA
{
...
}
public class ViewModelB
{
ViewModelA messageSender{get;set};
...
}
Требование: мне нужно отправить сообщение из ViewModelA в ViewModelB.
Проблема: существует несколько экземпляров ViewModel, которые создаются и добавляются в коллекцию экрана. Мне нужно отправить сообщение только конкретному экземпляру ViewModelB. Все остальные экземпляры viewmodel должны игнорировать сообщение.
Примечание. В приведенном выше примере кода я отправляю сообщение из объекта viewmodel messageSender
вмещающий класс. Поэтому сообщение следует отправлять только экземпляру родительского объекта.
Вопрос
- Есть ли какая-либо встроенная функциональность, доступная в caliburn micro framework, чтобы справиться с этой ситуацией?
- Если нет, то есть ли метод уникальной идентификации экземпляра viewmodel для обработки сообщения?
3 ответа
Я не думаю, что в Caliburn EventAggregator это встроено. PRISM EventAggregator позволяет передавать функцию фильтра, а MVVMLight Messenger использует объект токена.
Я думаю, в Caliburn вам нужно было бы включить что-то в сообщение, чтобы подписчики могли решить, обрабатывать ли они сообщение или нет.
IHandle<T>
используется в классе, который должен "действовать" на сообщение, которое вы публикуете с помощью IEventAggregator, обычно в качестве инъекции. не забывайте подписываться и отписываться в соответствии с Активировать и деактивировать, когда он либо становится неактивным, либо закрывается. Только тот класс, который наследует IHandle<T>
с его "уникальной" подписью откликнется на трансляцию. Теперь, конечно, если вы несколько IHandle<string>
Например, все виртуальные машины будут пытаться обработать отправленное сообщение, если они были подключены для этого.
//Handle<T> for any built-in type or something you create like MessageEvent etc.
public class ViewModelB : Screen, IHandle<string>
{
public ViewModelB(IEventAggregator events){
_event = events;
_events.Subscribe(this);
}
private void Handle(string t){
MessageBox.Show(t);
}
}
public class ViewModelA : Screen
{
private readonly IEventAggregator _event;
public ViewModelA(IEventAggregator events)
{
_event = events;
_event.Subscribe(this);
}
public void SomethingWasClicked()
{
_event.PublishOnUIThread("Hello, World!");
}
}
Чтобы уточнить, что сказал mvermef, вам необходимо реализовать IHandle<T>
интерфейс в моделях представления, которые будут обрабатывать определенные сообщения. Так как он выбрал string
для типа сообщения, вам придется проанализировать сообщение в ViewModelB
чтобы справиться с этим, если другие модели представления реализовали IHandle<string>
интерфейс. Возвращаясь к вашему примеру и сделав его более конкретным для ViewModelB
, вы можете наследовать от базового класса, который обрабатывает сообщения на основе строк.
public class StringMessageEventBase
{
private string _Message;
public StringMessageEventBase()
: this(null) { }
public StringMessageEventBase(string message)
{
_Message = message;
}
public string Message
{
get { return _Profile; }
set { _Profile = value; }
}
}
public class ViewModelBMessageEvent : StringMessageEventBase
{
public ViewModelBMessageEvent(string message)
: base(profile) {}
}
Теперь, если вы реализуете IHandle<ViewModelBMessageEvent>
по вашему мнению модель, ViewModelB
, тогда только случаи ViewModelB
обработает сообщение.
public class ViewModelB : IHandle<ViewModelBMessageEvent>
{
private readonly IEventAggregator _Aggregator;
public ViewModelB(IEventAggregator aggregator)
{
if (aggregator == null)
throw new ArgumentNullException("aggregator");
_Aggregator = aggregator;
_Aggregator.Subscribe(this);
}
public void Handle(ViewModelBMessageEvent message)
{
// do some thing with your message here
var msg = message.Message;
}
}