依赖注入在 MVVM 中以对话框形式启动视图

Mik*_*kel 5 c# wpf dependency-injection unity-container

我需要一些关于如何处理 ViewModel 中的依赖注入的建议。我的 viewModelMenuViewModel有一个ICommand方法,当用户单击视图中的按钮时将运行该方法。该方法将打开一个新窗口。该方法如下所示。

public void bookingCommand_DoWork(object obj)
{
    BookingView bookingView = new BookingView();
    BookingViewModel model = new BookingViewModel();
    bookingView.DataContext = model;

    bookingView.ShowDialog();
}
Run Code Online (Sandbox Code Playgroud)

BookingView它创建和的实例BookingViewModel。我正在尝试使用依赖项注入而不是创建这样的实例。

菜单视图模型

public class MenuViewModel : IViewMainWindowViewModel
{
    //commands
    public ICommand bookingCommand { get; set; }

    public MenuViewModel()
    {
        bookingCommand = new RelayCommand(bookingCommand_DoWork, () => true);
    }

    public void bookingCommand_DoWork(object obj)
    {
        BookingView bookingView = new BookingView();
        BookingViewModel model = new BookingViewModel();
        bookingView.DataContext = model;

        bookingView.ShowDialog();
    }
}
Run Code Online (Sandbox Code Playgroud)

IViewMainWindowViewModel是一个空接口,它在我的 MainWindow 和 MenuViewModel 之间建立了契约。

我正在使用的 Unity 启动方法

protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        IUnityContainer container = new UnityContainer();
        container.RegisterType<IViewMainWindowViewModel, MainWindow>();
        container.RegisterType<IViewMainWindowViewModel, MenuViewModel>();
        container.RegisterType<IViewBookingViewModel, BookingViewModel>();
        container.RegisterType<IViewBookingViewModel, BookingView>();

        container.Resolve<MainWindow>().Show();
        //Do the same actions for  all views and their viewmodels
    }
Run Code Online (Sandbox Code Playgroud)

嗯,我的MenuViewModel取决于BookingView& BookingViewModel

我应该将其注入到构造函数中还是?

希望有人能给一些建议。

更新(目前为我工作)

到目前为止我所做的:

1. 应用程序类

public partial class App : Application
{
    public IUnityContainer _container;

    public IUnityContainer UnityContainer
    {
        get
        {
            if (_container == null)
            {
                _container = new UnityContainer();

            }
            return _container;
        }
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        _container = new UnityContainer();
        _container.RegisterType<IViewMainWindowViewModel, MainWindow>();
        _container.RegisterType<IViewMainWindowViewModel, MenuViewModel>();
        _container.RegisterType<IViewBookingViewModel, BookingView>();
        _container.RegisterType<IViewBookingViewModel, BookingViewModel>();

        _container.RegisterType(typeof(IDialogService<>), typeof(DialogService<>));

        _container.Resolve<MainWindow>().Show();
    }

}
Run Code Online (Sandbox Code Playgroud)

2. 创建 IDialogService 并从 App 类导入容器。

public interface IDialogService<T>
{
    void Show();
    void ShowDialog();
}

public class DialogService<T> : IDialogService<T> where T : Window
{

    public void Show()
    {
        var container = ((App)Application.Current).UnityContainer;
        container.Resolve<T>().Show();
    }

    public void ShowDialog()
    {
        var container = ((App)Application.Current).UnityContainer;
        container.Resolve<T>().ShowDialog();
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在在 Show 和 ShowDialog 方法中遇到错误。

“T”不包含“Show”/“ShowDialog”的定义,并且没有接受类型 T 的第一个参数的扩展方法“Show”/“ShowDialog”。

3. 在MenuViewModel中注入服务

public class MenuViewModel : IViewMainWindowViewModel
{
    //commands
    public ICommand bookingCommand { get; set; }

    //entities
    private IDialogService<BookingView> _dialogService;


    public MenuViewModel(IDialogService<BookingView> dialogService)
    {
        // Injecting
        _dialogService = dialogService;

        bookingCommand = new RelayCommand(bookingCommand_DoWork, () => true);
    }

    public void bookingCommand_DoWork(object obj)
    {
        _dialogService.ShowDialog();

    }
}
Run Code Online (Sandbox Code Playgroud)

Nit*_*tin 4

在某些情况下,我们必须将视图作为模型或无模式对话框启动。为了将事物保持在 MVVM 的边界内,我宁愿创建一个单独的服务来将视图作为对话框启动,以便它可以在整个应用程序中以通用的方式使用。并将通过想要启动任何对话框的构造函数将此服务注入到 ViewModel 中。

public interface IDialogService<T>
{
    void Show();
    void ShowDialog();
}

public class DialogService<T> : IDialogService<T> where T : Window
{
    public void Show()
    {
        container.Resolve<T>().Show();
    }

    public void ShowDialog()
    {
        container.Resolve<T>().ShowDialog();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我将将此服务注入到相应的视图模型中。

public class MenuViewModel : IViewMainWindowViewModel
{
    //commands
    public ICommand bookingCommand { get; set; }

    private IDialogService<BookingView> _dialogService;
    public MenuViewModel(IDialogService<BookingView > dialogService)
    {
        _dialogService = dialogService
        bookingCommand = new RelayCommand(bookingCommand_DoWork, () => true);
    }

    public void bookingCommand_DoWork(object obj)
    {
        //Since you want to launch this view as dialog you can set its datacontext in its own constructor.

        _dialogService.ShowDialog();
    }
}
Run Code Online (Sandbox Code Playgroud)

在 App.xaml.cs 中,您可以定义如下所示的属性。然后你可以使用属性UnityContainer,然后在服务中你可以获得像这样的容器var container = ((App) Application.Current).UnityContainer;

    public IUnityContainer _container;
    public IUnityContainer UnityContainer
    {
        get
        {
            if (_container == null)
            {
              _container = new UnityContainer();

            }
            return _container;
        }
    }
Run Code Online (Sandbox Code Playgroud)

这样做将有助于保持虚拟机的可测试性,因为您也可以通过测试注入服务的模拟。