Rahul
Rahul

Reputation: 2741

caliburn.micro eventAggregator: Handling message in Screen Collection

I have following code in my caliburn micro application. I'm using eventAggregator to send messages from one view model to another.

Consider following code:

public class ShellViewModel : Conductor<IWorkspace>.Collection.OneActive, IShell
{
   ...
}

public class ViewModelA
{
   ...
}

public class ViewModelB
{
   ViewModelA messageSender{get;set};
   ...
}

Requirment: I need to send message from ViewModelA to ViewModelB.

Problem: There are multiple ViewModel instance are created and added to screen collection. I need to send the message only to a particular ViewModelB instance. All other viewmodel instance should ignore the message.

Note: In above code example I'm sending message from viewmodel object messageSender to enclosing class. So the message should be sent to the parent object's instance only.

Question

  1. Is there any build in functionality available in caliburn micro framework to handle this situation?
  2. If not is there any technique to uniquely identify the viewmodel instance to process the message?

Upvotes: 0

Views: 2122

Answers (3)

Mark Polsen
Mark Polsen

Reputation: 149

To elaborate on what mvermef said, you need to implement the IHandle<T> interface in the view models that will handle the specific messages. Since he chose a string for the message type, you'd have to parse the message in ViewModelB to handle it if other view models implemented the IHandle<string> interface. Going back to your example and making it more specific for ViewModelB, you could inherit from a base class that handles string-based messages.

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) {}
}

Now if you implement IHandle<ViewModelBMessageEvent> in your view model, ViewModelB, then only instances of ViewModelB will handle the message.

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

Upvotes: 0

mvermef
mvermef

Reputation: 3914

IHandle<T> is used on the class that needs to "Act" on the message, you publish using IEventAggregator, usually as an injection. remember to Subscribe and Unsubscribe according to Activate and Deactivate when it either goes inactive or gets closed. Only the class that is inheriting the IHandle<T> with its "unique" signature will respond to the broadcast. Now of course if you multiple IHandle<string>'s for example then all VM's will try to process the message that was sent, if they were wired up to do so.

//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!");
     }
}

Upvotes: 1

Glen Thomas
Glen Thomas

Reputation: 10744

I don't think Caliburn EventAggregator has this built in. PRISM EventAggregator allows a filter func to be passed in and MVVMLight Messenger uses a token object.

I guess in Caliburn you would need to include something in the message to allow the subscribers to decide whether they should process the message or not.

Upvotes: 1

Related Questions