简体   繁体   中英

MVVM Light: how to send a parameter to ViewModel (when opening new window)?

I am trying to learn MVVM with MVVM Light Toolkit in WPF. But I am stuck on one simple problem.

I have an AddEditProfileWindow which basically has a textbox for profile name and a confirm button. It adds new profile to database table or updates name of existing profile.

In MainWindow/MainViewModel I have a list of profiles and two buttons: "Add Profile" and "Edit Selected Profile". They both open this window via commands + messages. For example here is command for the "Add Profile" button

    public RelayCommand OpenAddProfileWindowCommand
    {
        get
        {
            return _openAddProfileWindowCommand ?? (_openAddProfileWindowCommand = new RelayCommand(
                () => { Messenger.Default.Send(new NotificationMessage("OpenAddProfile")); }));
        }
    }

and it's receiver in MainWindow code behind

private void MessageReceived(NotificationMessage msg)
{
    if (msg.Notification == "OpenAddProfile")
    {
        var window = new AddEditProfileWindow();
        window.Owner = this;
        window.ShowDialog();
    }
}

So the problem is that I need to somehow pass a parameter to the AddEdit... Window/ViewModel (set IsEditing bool property in ViewModel for example) to change window behavior and customize it a bit (change title and the confirm button text to "Add" or "Update"). Also for updating I need Profile object (or at least Id) of selected record.

For creating ViewModels I use ViewModelLocator and Unity

    public ViewModelLocator()
    {
        var container = new UnityContainer();

        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));

        container.RegisterType<MainViewModel>(new ContainerControlledLifetimeManager()); // singleton
        container.RegisterType<AddEditProfileViewModel>(); 
    } 

    public AddEditProfileViewModel AddEditProfile
    {
        get
        { return ServiceLocator.Current.GetInstance<AddEditProfileViewModel>();  }
    }

I have read a lot of similar threads and examples but still don't understand how should I pass parameters to view models. Some answers suggest creating view models on app startup (and make them singletons) in the ViewModelLocator and then I can send message before opening. But looks like not very clean and also I will need to reset view models before opening (via Cleanup() probably).

Is there any better/easier/cleaner approach?

In my opinion, Messenger and getting AddEditProfileViewModel from IoC are not suitable in this scenario. First you send message from a UI's DataContext to UI. Messenger works between loosely coupled components and usually on the same level, view model and view model for example. If you want view model to notify view, you can use InteractionRequest from Prism. Second, AddEditProfileViewModel can be considered as a temporary, based on its view is a modal dialog, so its creation might depend on the environment that creates it.

One approach, using shared service, maybe called IDialogService, which has a method might called ShowAddEditDialog. Your main view model gets this service from IoC and calls it when executing command, add/edit. When calling the method, main view model also creates AddEditProfileViewModel and passing states, such as add/edit, existing profile, etc.

Another approach, using application controller, if you still want to keep Messenger and IoC. You still can use Messenger here but it is not the view who listens to messages, instead it is an application controller. Now, application controller, main view model, AddEditProfileViewModel and AddEdit window are all resolved from IoC container. The application controller holds both view models and listen to the message. When it got message from main view model, it updates states on AddEditProfileViewModel, resolve dialog, set DataContext and show the dialog. You can put the application controller instance in MainWindow code behind or anywhere since once it gets resolved from IoC, it is autonomous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM