Passing parameters between viewmodels

In my app I have 2 views. List(GridView) and Form. I am changing views as proposed in this thread: WPF MVVM switch usercontrols

Now I have a problem how to pass id of selected item after click edit to show new View with the edit form.

Simple application to list all items, add new, delete and edit. How can I do this in MVVWM?


UPDATE

I just want to create a simple application, that has menu on the left with:

  1. List
  2. Add new.

When click List, it shows UC with list and 3 buttons: Add, Edit, Delete. After click add, edit it shows UC with Form with specific values (while editing). How can I achieve this??


Solution 1:

As far as I understand, you want something like this:

Main screen showing the list So that when you click Add, it shows this: Main screen showng the add form

Right?

So you need the following behaviour:

  • Add doesn't needs any ID.
  • List must reload after Add finishes.
  • Edit receives the list's selected item ID .
  • List must reload after Add finishes.

I will assume that you are working with some repository.

I propose the following MVVM structure:

  • MainViewModel: The DataContext for the main screen.
    • BaseViewModel RightViewModel: The container for viewmodels shown on the right part of the screen.
    • ICommand ViewListCommand: Shows the list by creating a new instance of ListViewModel and assigning it to the BaseViewModel property.
    • ICommand AddNewCommand: Shows the addnew screen by creating a new isntance of AddViewModel and assigning it to the BaseViewModel property.

Then:

  • ListViewModel: The DataContext for the right part of the screen when List is clicked.
    • List<Items> Items: Provides the items to be shown.
    • Item SelectedItem: The property that will be binded to the SelectedItem on the UI.
    • ICommand EditCommand: The command that will get the selected item and notify the MainViewModel that has to be edited.

So at some point, a viewmodel will receive a notification from a child viewmodel (i.e. list will tell main to edit somethin). I recommend to do this by using events as:

public class Item
{
    public string Name { get; set; }
}

public class ItemEventArgs : EventArgs
{
    public Item Item { get; set; }

    public ItemEventArgs(Item selectedItem)
    {
        this.Item = selectedItem;
    }
}

public class BaseViewModel
{

}

public class ListViewModel : BaseViewModel
{
    public event EventHandler<ItemEventArgs> EditItem;

    public Item SelectedItem { get; set; }

    public ICommand EditItemCommand { get; private set; }

    public ListViewModel()
    {
        this.EditItemCommand = new DelegateCommand(() => this.EditItem(this, new ItemEventArgs(this.SelectedItem)));
    }
}

public class EditViewModel : BaseViewModel
{

}

public class MainViewModel
{
    public BaseViewModel RightViewModel { get; private set; }

    public ICommand ViewListCommand { get; private set; }

    public MainViewModel()
    {
        this.ViewListCommand = new DelegateCommand(() =>
        {
            // unhook possible previous events
            var listViewModel = new ListViewModel();
            listViewModel.EditItem += listViewModel_EditItem;
            this.RightViewModel = listViewModel;
        });
    }

    void listViewModel_EditItem(object sender, ItemEventArgs e)
    {
        // unhook possible previous events
        var editViewModel = new EditViewModel();
        this.RightViewModel = editViewModel;
    }

}

The xaml binding is not necessary since it will be quite forward.

This is a very basic example about how I think this kind of stuff can be handled. The important thing here is to properly unhook the events, otherwise you can run into problems.

For this kind of stuff you can also have a look at Reactive UI.

Solution 2:

If you have a common parent of the view models, then you can use that parent to pass parameter values for you. Simply set up one or more delegates in the relevant view models:

In the view model with the relevant parameter to update... let's call it ParameterViewModel:

public delegate void ParameterChange(string parameter);

public ParameterChange OnParameterChange { get; set; }

In the parent:

ParameterViewModel viewModel = new ParameterViewModel();
viewModel.OnParameterChange += ParameterViewModel_OnParameterChange;
ListMenu.Add(viewModel);
// Add other view models

Back in ParameterViewModel when the parameter changes:

public string Parameter
{
    get { return parameter; }
    set
    {
        parameter = value;
        NotifyPropertyChanged("Parameter");
        // Always check for null
        if (OnParameterChange != null) OnParameterChange(parameter);
    }
}

Now in the parent view model:

public void ParameterViewModel_OnParameterChange(string parameter)
{
    // Do something with the new parameter data here
    AnotherViewModel anotherViewModel = (AnotherViewModel)ListMenu[someIndex];
    anotherViewModel.Parameter = parameter;
}

You can find out more about using delegate objects from the Delegates (C# Programming Guide) page on MSDN.