c# - 依赖注入(inject)以在 MVVM 中以对话框形式启动 View

标签 c# wpf dependency-injection unity-container

我需要一些关于如何在我的 ViewModel 中处理依赖注入(inject)的建议。我的 viewModel MenuViewModel 有一个 ICommand 方法,该方法将在用户单击 View 中的按钮时运行。此方法将打开一个新窗口。方法如下所示。

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

    bookingView.ShowDialog();
}

它创建一个 BookingViewBookingViewModel 的实例。我正在尝试使用依赖项注入(inject)而不是像这样创建实例。

菜单 View 模型

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();
    }
}

IViewMainWindowViewModel 是一个空接口(interface),它在我的 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
    }

好吧,我的 MenuViewModel 依赖于 BookingViewBookingViewModel

我应该将其注入(inject)构造函数还是?

希望有人能给点建议。

更新(目前为我工作)

到目前为止我做了什么:

<强>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();
    }

}

<强>2。从 App 类创建 IDialogService 并导入容器。

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();
    }
}

我现在在 Show 和 ShowDialog 方法中遇到了一个错误

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

<强>3。在 MenuViewModel 中注入(inject)服务

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();

    }
}

最佳答案

在某些情况下,我们必须将 View 作为模型或无模式对话框启动。为了保持 MVVM 的边界,我宁愿创建一个单独的服务来将 View 作为对话框启动,以便它可以在整个应用程序中以通用方式使用。并将通过想要启动任何对话框的构造函数将此服务注入(inject)到 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();
    }
}

现在我将此服务注入(inject)相应的 View 模型。

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();
    }
}

在 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;
        }
    }

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

关于c# - 依赖注入(inject)以在 MVVM 中以对话框形式启动 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36642073/

相关文章:

.net - 通过 WCF 传递图像并将它们显示在 WPF 数据网格中

c# - CaSTLe Windsor IoC 将属性注入(inject)构造函数

c# - LINQ to Entities 仅支持使用 IEntity 接口(interface)转换 EDM 原语或枚举类型

c# - 数据触发器 wpf 不工作

c# - 执行位于 JavaScript 代码隐藏中的函数?

wpf - 我应该在哪里设置 DataContext - 代码隐藏或 xaml?

dependency-injection - 依赖注入(inject)刷新逻辑位置

c# - 依赖注入(inject)和库/框架

c# - 模拟管理系统?

c# - 使用 C# 远程使用 WUA