views:

45

answers:

1

Hey.

I'm building my first app using MVVM and I stuck. Using the messenger to communicate other ViewModels about some changes was working ok until I tried to build an observablecollection of objects. I have a class (myClass) that contains a list (innerList). Elements of innerLists should send message to it's parent (to communicate that they changed or should be deleted). I'm sending a message from the innerList object. This message is registered in the myClass.

The problem is that I need to create ObservableCollection of myClass objects. As I understand the idea of sending - receiving messages, every instance of myClass will receive the message sent from the element of innerList. The goal is to be able to receive the message only in the parent myClass object, and not every object of myClass.

The structure I described is much more complicated so that's just the sketch of the situation. The question - is it possible to send a message only to parent object using Messenger's Send Register functionality. Maybe it should be solved in some other way?

Below is how the two classes are built. I shortened it to only this what's important here.

public class ObjTypeListVM : ViewModelBase
{
    private ObservableCollection<ObjTypeVM> objTypeList = new ObservableCollection<ObjTypeVM>();

    public ObjTypeListVM()
    {
        Messenger.Default.Register<Messages.ObjTypeModifiedMsg>(this, ObjTypeModified);
    }

    public ObservableCollection<ObjTypeVM> ObjTypeList
    {
        get { return objTypeList; }
    }

    public void ObjTypeModified(Messages.ObjTypeModifiedMsg msg)
    { 
        switch (msg.Type)
        {...

            case "delete":
                Delete(msg.ObjType);
                break;
            default:
                break;
        }
    }
    public void Delete(ObjTypeVM objType)
    {...
        ObjTypeList.Remove(objType);
    }
}


public class ObjTypeVM : ViewModelBase
{
    private XmlSTSLib.ObjType objType;
    int objTypeId;

    private RelayCommand deleteItemCmd;

    public ObjTypeVM(ObjType _objType, int _objTypeId)
    { ... }


    public int ObjTypeId
    {
        get { return this.objTypeId; }
        set { this.objTypeId = value; RaisePropertyChanged("ObjTypeId"); }
    }


    public RelayCommand DeleteItemCmd
    { 
        get
        {
            if (deleteItemCmd == null)
            {
                deleteItemCmd = new RelayCommand(Delete);
            }
            return deleteItemCmd;
        }
    }

    public void Delete()
    {
        Messenger.Default.Send<Messages.ObjTypeModifiedMsg>(new Messages.ObjTypeModifiedMsg(this, "delete"));
    }
}
+1  A: 

Assuming you use MVVM-Light from Galasoft (just a guess ;P), there are several ways.

One, by assigning a token which both objects know, and sending the message together with that token. Only recipients which registered with that token will receive the message.

Two, specify the Target property of the message object, and have the recipients check it. All registered recipients will receive the message, but they can choose whether they want to react or not based on the Target property of the message.

Good job on using the Messaging system, it rocks ;)

Alex Paven
The question is performance in this case. It's not a problem if in let's say ten objects I check if this object is a proper receiver. However if there will be 10000 or more instances of objects that have certain message type registered, performance can be an issue.
Bartek
In that case, maybe you should avoid the messaging system and use standard practices and events, like INotifyPropertyChanged and INotifyCollectionChanged for notifications like what you described; you could combine them into an ObservableItemCollection (the name comes from RIA Services I think), which is an observable collection that also raised property changed events on behalf of the objects it contains. Of course, that means you must register to each item's PropertyChanged event when it is added to the collection, and as such you will still take a performance hit, but lower.
Alex Paven