RyanWang
RyanWang

Reputation: 178

How to pass a parameter from a viewmodel to its parent viewmodel

First View is a listview including some items.

eg. item0, item1, item2

When click a "new" button, the second view will be shown.

Then click a "save" button and input a name(eg. item3). The "item3" will be save in seconde viewmodel

After saving success. The first view will refresh and show "item3"

How to pass name "item3" from second viewmodel to first viewmodel for showing in first view?

Upvotes: 1

Views: 846

Answers (2)

Pap
Pap

Reputation: 148

Use the Messenger Plugin in MVVMCross. The First VM registers for a message. The 2nd VM Publishes(Notifies) the 1st one by publishing a Message of the Message type(class) registered. For example:

1st VM In order to use the messenger plugin you need to register it first, using Injection as follows:

private readonly IMvxMessenger _messenger; // VM Instance var
private MvxSubscriptionToken myToken;

public FirstViewModel(IDataService dataService, IMvxMessenger messenger)
{
            // Registers the DataService(SQLite Plugin) and the Messenger Service Plugin
            _dataService = dataService;
            _messenger = messenger;

            // Suscribe to the Meessage and pass it the name of a method to be called when the 2nd VM(the Publisher), publishes(notifies) a MyMessage to all Subscribers...
             myToken = _messenger.Subscribe<MyMessage>( OnMyMessageArrived );
}

private void OnMyMessageArrived( MyMessage p_myMessage )
{
  // Set the 1st VM's property from p_myMessage
  MyProperty = p_myMessage.Item3
}

And the MyMessage class should look like this:

 public class MyMessage : MvxMessage
    {
        public MyMessage( object sender, string p_item3 ): base( sender )
        {
            Item3 = p_item3;
        }

        public string Item3 { private set; get; }
    }

And the 2nd VM, when ready to send the value back, it should Publish the MyMessage with the value to be passed back to 1st VM(and any subscribers) as follows:

_messenger.Publish( new MyMessage( this, item3 ) );

It's a good practice to have the Subscribers to unsubscribe from any messages they subscribe to, so back in the 1st VM, perhaps just before you close it you should do:

_messenger.Unsubscribe<MyMessage>( myToken );

For a more complete example checkout Stuart's N=9 video and associated sample. Here's the link to both:

http://slodge.blogspot.com/2013/05/n9-getting-message-n1-days-of-mvvmcross.html

R,

Pap

Upvotes: 3

Dai
Dai

Reputation: 155145

I'm not familiar with mvvmcross, so I'll answer your question using general M/VM/V/C architecture patterns:

Views and ViewModels shouldn't be aware of each other, that's the Controller's job. Your FirstView should alert its controller that the user clicked New and it is the controller's responsibility to then create and manage your SecondView.

The process would be like this (abstract, psuedocode-ish):

void ControllerAction() {
    using(View listView = new MyListView() ) {

        ListViewViewModel listViewVM = CreateListViewVM();
        listViewVM.NewClicked = () => this.NewClicked(listViewVM); // wiring-up ViewModel events via anonymous methods

        listView.SetViewModel( listViewVM );
        listView.ShowModal();
    }
}

void NewClicked(ListViewViewModel parentViewViewModel) {
    using(View newEntryView = new NewEntryView()) {
        if( newEntryView.ShowDialog() == DialogResult.OK ) {
            parentViewViewModel.Refresh();
            parentViewViewModel.SelectedItem = newEntryView.NewItemText; // passing the new item's name
        }
    }
}

Upvotes: 0

Related Questions