简体   繁体   中英

WPF/MVVM navigation with direct ViewModel switching

I've started writing my first WPF/MVVM and as many other people have found, dealing with navigation between views is rather confusing.

I've been searching for a while and most of the topics either recommend using MVVM Light/PRISM, or come up with solutions similar to one from here .

I'm trying to approach an MVVM navigation mechanism in which I can switch directly from one view to another view (without using the datatemplate switch from the parent window). Let's say, I have an app with a main window loading dynamic content from different usercontrols (views).

The MainWindowViewModel would have a CurrentV property pointed to, say, UserListV and a CurrentVM property pointed to UserListVM. Now that I select one user from the list and click on the View button to view that user details in another screen of the same window. This should allow me to switch to the UserV with UserVM as data context.

I wonder how should I, while being on UserListVM, make a call to MainWindowViewModel to update the CurrentV and CurrentVM values, and switching the window to the UserV accordingly?

Any suggestion of a better idea is more than welcome!

Thank you very much!

I use a messaging service for communication between ViewModels, while still keeping them decoupled. If you are using MVVMLight, it comes with one. I prefer not to use an MVVM framework, and write my own messaging service. Here is an example of one from a recent project:

public class MessageService : IMessageService
{
    private List<IMessageSubscription> subscribers; //list of subscription objects registered

    public MessageService()
    {
        subscribers = new List<IMessageSubscription>();
    }

    public void Subscribe<T>(string message, Action<T> action)
    {
        subscribers.Add(new MessageSubscription<T>() 
        { 
            Message = message, 
            MessageActionWithArgs = action 
        });
    }

    public void Subscribe(string message, Action action)
    {
        subscribers.Add(new MessageSubscription<bool>() 
        { 
            Message = message, 
            MessageActionNoArgs = action 
        });
    }

    public void Send<T>(string message, T args)
    {
        IEnumerable<IMessageSubscription> matches = subscribers.Where(x => x.Message == message && x.PayLoadType == typeof(T));

        foreach (IMessageSubscription sub in matches.ToList())
        {
            sub.InvokeMessageAction((T)args);
        }
    }

    public void Send(string message)
    {
        IEnumerable<IMessageSubscription> matches = subscribers.Where(x => x.Message == message);

        foreach (IMessageSubscription sub in matches.ToList())
        {
            sub.InvokeMessageAction();
        }
    }
}

So, for example, MainViewModel would listen for a message such as "ActiveViewModelChangeRequest", and other viewmodels would send that message when they need to become active. So, in MainViewModel you would have something like this:

public MainViewModel()
{
    messageService.Register<ViewModelBase>("ActiveViewModelChangeRequest", UpdateActiveViewModel);
}

private void UpdateActiveViewModel(ViewModelBase viewModel)
{
     this.CurrentVM = viewModel;
}

And then in UserListVM you would have:

private void OnUserSelect(object sender, UserSelectionEventArgs e)
{
     UserVM viewModel = new UserVM(SelectedUser);
     messageService.Send<ViewModelBase>("ActiveViewModelChangeRequest, viewModel);
}

There's a lot of reading material available on the messenger pattern for MVVM applications. I would suggest reading up on this.

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