The best approach to create new window in WPF using MVVM

后端 未结 6 1890
無奈伤痛
無奈伤痛 2020-12-04 07:21

In the neighbour post: How should the ViewModel close the form? I\'ve posted my vision how to close windows with MVVM usage. And now I have a question: how to open them.

6条回答
  •  遥遥无期
    2020-12-04 07:42

    I'm a bit late, but I find existing answers insufficient. I will explain why. In general:

    • it's ok to access ViewModels from View,
    • it's wrong to access Views from ViewModels, because it introduces circular dependency and makes the ViewModels hard to test.

    Benny Jobigan's anwer:

    App.Container.Resolve().ShowDialog();
    

    this actually does not solve anything. You are accessing your View from ViewModel in a tigtly coupled fashion. The only difference from new MyChildView().ShowDialog() is that you went trough a layer of indirection. I don't see any advantage over directly calling the MyChildView ctor.

    It would be cleaner if you used interface for the view:

    App.Container.Resolve().ShowDialog();`
    

    Now the ViewModel is not tigtly coupled to the view. However I find it quite impractical to create interface for each view.

    arconaut's anwer:

    Messenger.Default.Send(new DialogMessage(...));
    

    it's better. It seems like Messenger or EventAggregator or another pub/sub patterns are universal solution for everyhing in MVVM :) The disadvantage is that it's harder to debug or to navigate to DialogMessageHandler. It's too indirect imho. For example, how would you read output form the Dialog? by modifying DialogMessage?

    My Solution:

    you can open window from MainWindowViewModel like this:

    var childWindowViewModel = new MyChildWindowViewModel(); //you can set parameters here if necessary
    var dialogResult = DialogService.ShowModal(childWindowViewModel);
    if (dialogResult == true) {
       //you can read user input from childWindowViewModel
    }
    

    DialogService takes just dialog's ViewModel, so your viewmodels are totally independent from Views. At runtime, DialogService can find appropriate view (using naming convention for example) and shows it, or it can be easily mocked in unit tests.

    in my case I use this interfaces:

    interface IDialogService
    {
       void Show(IDialogViewModel dialog);
       void Close(IDialogViewModel dialog); 
       bool? ShowModal(IDialogViewModel dialog);
       MessageBoxResult ShowMessageBox(string message, string caption = null, MessageBoxImage icon = MessageBoxImage.No...);
    }
    
    interface IDialogViewModel 
    {
        string Caption {get;}
        IEnumerable Buttons {get;}
    }
    

    where DialogButton specifies DialogResult or ICommand or both.

提交回复
热议问题