Updating a viewmodel from another viewmodel

2019-02-13 13:17发布

问题:

I have two ViewModels one is attached to a main window and the other is attached to child window that is opened by clicking on a button on the main window. The child window contains a list of items and I want to select an item and display it in the main window by updating the main window viewmodel. What is the best way to accomplish this. Thanks!

回答1:

There are any number of ways to do this.

  • Pass a reference to the main/parent view model into the child and have the child call the main view model.

  • Have the child view model fire an event that the parent subscribes to.

  • Use a messenger/mediator to communicate between the two. The parent subscribes, the child posts the message. This provides loose coupling.

  • Set the main view model up as a global service. Register it somehow. Have the child look up the service (requiring global services is a pretty common problem) and then call something on the global/common interface.

From my experience, the simplest method would be #2. Define an event on the child view model. The parent will have to look up the child (I don't know if it contains it or how your view models are constructed) and subscribe to the event.



回答2:

The standard way to communicate between ViewModels is to use Messaging of some sort. One good implementation of this is the MVVM Light Toolkit

Here's some (random) code using the default messenger therefrom:

//Registering:
Messenger.Default.Register<IEnumerable<BookViewModel>>(this, true, fillSourceWith);
Messenger.Default.Register<DisplayModeEnum>(this, ChangeMainTemplates);
//with a specific "token"
Messenger.Default.Register<object>(this, MessageTokens.ClearList, o => BookSource.Clear()); 

//Sending
Messenger.Default.Send<List<BookViewModel>>(newBooks);
Messenger.Default.Send<DisplayModeEnum>(DisplayModeEnum.MediumLayout);
Messenger.Default.Send<object>(null, MessageTokens.ClearList);


回答3:

Best way to do it is to have some kind of reference from child to parent and to update this parent when closing the child.

Or you can have some kind of event on child and let parent listen on this event. You then raise this event when child closes.

Messaging is used when both ViewModels are logicaly unrelated.

[rant] Dont people even know basic principles of OOP or what?? [/rant]



回答4:

I had the same problem a few days before ;-)

Finally I used a mediator to communicate both view-models. On fact I used the Messenger from MVVM Light.

public void Search(object parameter)
        {
            ChildWindow window = new ChildWindow();

            SearchWindow pageSearch = new SearchWindow();

            window.Content = pageSearch;
            window.Show();

            Messenger.Default.Register<Messages.CloseWindowMessage>(this, action => this.closeWindow(action));
        }

After that I defined the Message with everything I needed to know from main window:

public class CloseWindowMessage : MessageBase
    {
        public bool Result { get; set; }
        public Model.Selected Selected { get; set; }
    }

Finally the message back from the childwindow you only have to register the message with result and the object you want to get back.

You should register from the code-behind of your view to close the window.



回答5:

I think best way to pass the message between two view models is event programming.