Skip to content

Custom dialog type locators

FantasticFiasco edited this page Aug 27, 2022 · 11 revisions

Most applications using MVVM follow some kind of naming convention for their views and view models, and the convention often also define where in the project structure one can assume to find them.

The default convention for this library is:

  • Regarding the name, a view model is named as its dialog with the addition of the suffix ViewModel
  • Regarding the namespace, either the dialog and its view model are located in the same namespace, or the dialog is located in a namespace that ends with Views and the view model is located in a namespace that ends with ViewModels

This convention will most definitely not conform to all applications, but indifferently of the convention used in your application you should still be able to use MVVM Dialogs. The way this library supports all possible conventions is by introducing a concept called dialog type locators.

The remainder of this topic will in detail guide you through building a custom dialog type locator that fits the convention used in a hypothetical application called MyAwesomeApplication. The application has the following structure.

MyAwesomeApplication
├── ComponentA
│   ├── MyDialog.xaml
│   └── MyDialogVM.cs
├── App.xaml
├── MainWindow.xaml
└── MainWindowVM.cs

The convention states that dialogs and their view models are placed in the same namespace, and view models are suffixed with VM. Before starting the implementation, lets see the interface of a dialog type locator.

/// <summary>
/// Interface responsible for finding a dialog type matching a view model.
/// </summary>
public interface IDialogTypeLocator
{
    /// <summary>
    /// Locates a dialog type based on the specified view model.
    /// </summary>
    Type Locate(INotifyPropertyChanged viewModel);
}

So for any given view model instance we are supposed to return the type of its corresponding dialog. Sounds easy enough, lets start with stubs.

public class MyCustomDialogTypeLocator : IDialogTypeLocator
{
    public Type Locate(INotifyPropertyChanged viewModel)
    {
        throw new NotImplementedException();
    }
}

The next step will be to implement some kind of logic that based on the type of the view model can calculate what its corresponding dialog type ought to be named according to our defined naming convention.

public class MyCustomDialogTypeLocator : IDialogTypeLocator
{
    public Type Locate(INotifyPropertyChanged viewModel)
    {
        Type viewModelType = viewModel.GetType();
        string viewModelTypeName = viewModelType.FullName;

        // Get dialog type name by removing the 'VM' suffix
        string dialogTypeName = viewModelTypeName.Substring(
            0,
            viewModelTypeName.Length - "VM".Length);
        
        throw new NotImplementedException();
    }
}

Ok, at this point we have the dialog type name, but the interface require the type to be returned, not its name. Lets do that and complete the implementation.

public class MyCustomDialogTypeLocator : IDialogTypeLocator
{
    public Type Locate(INotifyPropertyChanged viewModel)
    {
        Type viewModelType = viewModel.GetType();
        string viewModelTypeName = viewModelType.FullName;

        // Get dialog type name by removing the 'VM' suffix
        string dialogTypeName = viewModelTypeName.Substring(
            0,
            viewModelTypeName.Length - "VM".Length);
        
        return viewModelType.Assembly.GetType(dialogTypeName);
    }
}

At this point we have a complete implementation of a dialog type locator that conforms with the convention used in this application. The final step is to inject this locator to DialogService.

How that is done depends on the application. If you are using an IoC container you would configure the container to inject the locator when the container is resolving the dialog service. If you are running on bare metal you would configure this wherever you initialize your application.

For this application, lets assume that we are creating the dialog service in MainWindowViewModel.

public class MainWindowVM : INotifyPropertyChanged
{
    private readonly IDialogService dialogService;

    public MainWindowViewModel()
    {
        dialogService = new DialogService(dialogTypeLocator: new MyCustomDialogTypeLocator());
    }

    ...
}

And there we have it, a dialog service with a fully functional implementation of a dialog type locator!

For a complete working sample, please see Demo.CustomDialogTypeLocator.