Opening dialogs while adhering to the MVVM pattern seems to be one of the regular questions (here and elsewhere). I know there are frameworks like MVVM light who have answers to that problem, but I'm currently working on a very small personal project where I try to do most of the stuff myself for learning purposes.
To "force" myself to pay attention to the references, I decided to extract the view models from the UI project and put them into a separate assembly. The UI project references UI.ViewModels, but not the other way round. This led to me having problems with opening (modal) dialog windows.
Many people seem to be using a DialogService
which does something along the lines of:
internal class DialogService : IDialogService
{
public bool? OpenDialog(ViewModelBase vm)
{
Window window = new Window();
window.Content = vm;
return window.ShowDialog();
}
}
The corresponding window content can be inferred from the view model type by using a DataTemplate
.
In my scenario though, this doesn't work since the DialogService
needs to be in the UI project, but I have to call it from a view model. I could of course abuse DI/IoC to inject an IDialogService
implementation into my view models, but that's not what I want to do.
Is there any rigorous way to get this to work?
As an alternative, I have added the following code to my ViewModelBase
:
public abstract class ViewModelBase : INotifyPropertyChanged
{
...
public event Action<ViewModelBase, Action<bool?>> Navigate;
protected virtual void OnNavigate(ViewModelBase vm, Action<bool?> callback)
{
Navigate?.Invoke(vm, callback);
}
}
Obviously, there could be more overloads, other parameters, EventArgs
and so on; and I should probably put this into an interface as well. But it's just a 'thought' so far.
When creating a view instance (either via resolving or e.g. in the NavigationService
, see below), I can let a NavigationService
subscribe to that event and invoke the callback. Is this a problematic/bad idea? What are the cons of this? So far (without testing much), one thing I don't like is that I cannot continue in the next line after opening the dialog, but have to continue inside the callback code. That also makes it harder to follow the program flow by reading the code.
Any input is greatly appreciated! This is a very interesting topic, and since many many answers to these questions on SO are quite dated, I hope to learn more about the current best practices :)