WPF. MVVM. Как правильно реализовать команды используя IoC?

Помогите разобраться как правильно реализовать MVVM.

Не могу понять как правильно организовать открытие новых окон соответствующих нужным ViewModel-ям с помощью IoC-контейнеров.

Насколько я понимаю в MVVM ViewModel ничего не должна знать о View.

Проект: 1 Главный WPF-проект содержит два Windows:

  • MainWindow
  • DepartmentsWindow

Здесь же реализован метод ShowWindow выводящий новое окно для ViewModel-и

 public partial class App : Application
{
    public IServiceProvider Services { get; }
    public static App CurrentApp => (App)Application.Current;

    public App()
    {
        Services = ConfigureServices();
        var winService= Services.GetService<IWindowsService>();
        winService.Services = this.Services;
        winService.ShowWindow = ShowWindow;
        winService.ShowMessage = ShowMessage;
    }

    protected override void OnStartup(System.Windows.StartupEventArgs e)
    {
        base.OnStartup(e);

        var mainViewModel = Services.GetService<MainWindowViewModel>(); //создаём ViewModel главного окна
        var window = new MainWindow() { DataContext = mainViewModel };
        window.Show();
    }

    //Словарь в котором каждому ViewModel сопоставлен свой View
    static Dictionary<Type, Type> windowsTypesList = new Dictionary<Type, Type>();

    private static IServiceProvider ConfigureServices()
    {
        var services = new ServiceCollection();
        services.AddSingleton<IWindowsService, WindowsService>();

        services.AddTransient<MainWindowViewModel>();

        services.AddTransient<DepartmentsViewModel>();
        services.AddTransient<DepartmentsWindow>();
        windowsTypesList[ typeof(DepartmentsViewModel)] = typeof(DepartmentsWindow);
        return services.BuildServiceProvider();
    }

    /// <summary>
    /// Показать окно соответствующее ViewModel-и
    /// </summary>
    /// <param name="vm"></param>
    public void ShowWindow(Type vm)
    {
        var viewModel = Services.GetService(vm);

        Type? windowType;
        windowsTypesList.TryGetValue(vm, out windowType);

        var window = (Window)Services.GetService(windowType);

        window.DataContext = viewModel;
        window.ShowDialog();
    }

    
    public void ShowMessage(string mes)
    {
        MessageBox.Show(mes);
    }
}

2Есть "промежуточный" класс (в отдельной библиотеке WindowsServiceLibrary) с которым работают ViewModel. Класс сделан чтобы ViewModel ничего не знала о View и работала с ним, а не с View.

public interface IWindowsService
{
    public IServiceProvider? Services { get; set; }
    public Action<Type> ShowWindow { get; set; }
    public Action<string> ShowMessage{ get; set; }
}

 public class WindowsService:IWindowsService
{
    public IServiceProvider? Services { get; set; }
    public Action<Type> ShowWindow { get; set; }
    public Action<string> ShowMessage { get; set; }
}

3 Содержимое ViewModel (для главного окна программы) Здесь реализована команда!

 public partial class MainWindowViewModel
{
    IWindowsService service;
    public MainWindowViewModel(IWindowsService service)
    {
        this.service = service;
    }

    /// <summary>
    /// Команда. Показать окно "Все отделы"
    /// </summary>
    //для создания команды используем NET Community Toolkit 8.0! MVVM
    [RelayCommand]
    public void ShowAllDepartmentsWindow()
    {
        service.ShowWindow(typeof(DepartmentsViewModel));
    }
}

т.е. в этой команде мы "говорим" <Показать окно для следующей ViewModel - DepartmentsViewModel>

В окне стандартный вызов команды

<Button 
        Height="20" Width="120"
        Command="{Binding ShowAllDepartmentsWindowCommand}">Отделы</Button>

Правильно ли так реализовывать MVVM?

Правильно ли создавать класс типа WindowsService через который выводить новые окна?

Ведь он нужен только чтобы ViewModel ничего не знала о View.

Как правильно реализовать работу команд с помощью IoC?

Если есть пример полноценной реализации MVVM с КОМАНДАМИ и с IoC-контейнерами, скиньте пожалуйста.

Спасибо!


Ответы (0 шт):