C# 在MVVM中启动视图作为对话框的依赖项注入

C# 在MVVM中启动视图作为对话框的依赖项注入,c#,wpf,dependency-injection,unity-container,C#,Wpf,Dependency Injection,Unity Container,我需要一些关于如何在ViewModel中处理依赖项注入的建议。My viewModelMenuViewModel有一个ICommand方法,当用户单击视图中的按钮时将运行该方法。此方法将打开一个新窗口。方法如下所示 public void bookingCommand_DoWork(object obj) { BookingView bookingView = new BookingView(); BookingViewModel model = new BookingViewM

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

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

    bookingView.ShowDialog();
}
它创建
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();
    }
}
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();

    }
}
IViewMainWindowViewModel
是一个空界面,它在我的主窗口和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
    }
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();
    }
}
公共接口IDialogService
{
void Show();
void ShowDialog();
}
公共类DialogService:IDialogService其中T:Window
{
公开展览(
{
var容器=((App)Application.Current).UnityContainer;
container.Resolve().Show();
}
公共对话框()
{
var容器=((App)Application.Current).UnityContainer;
container.Resolve().ShowDialog();
}
}
现在我发现Show和ShowDialog方法有一个错误

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

3。将服务注入MenuViewModel中

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

    }
}
公共类菜单视图模型:IViewMainWindowViewModel
{
//命令
公共ICommand bookingCommand{get;set;}
//实体
私人IDialogService(对话服务);;
公共菜单视图模型(IDialogService dialogService)
{
//注入
_dialogService=dialogService;
bookingCommand=newrelaycommand(bookingCommand\u DoWork,()=>true);
}
公共作废簿记命令\u工作(对象对象对象)
{
_dialogService.ShowDialog();
}
}

编写以下代码行时:

BookingView bookingView = new BookingView();
BookingViewModel model = new BookingViewModel();
bookingView.DataContext = model;
bookingView.ShowDialog();
您违反了MVVM规则,因为
viewmodel
应该知道什么都不知道。我建议您使用
DataTemplates

如果要根据
视图模型
动态切换
视图
,可以使用
数据模板

<Window>
   <Window.Resources>
      <DataTemplate DataType="{x:Type ViewModelA}">
         <localControls:ViewAUserControl/>
      </DataTemplate>
      <DataTemplate DataType="{x:Type ViewModelB}">
         <localControls:ViewBUserControl/>
      </DataTemplate>
   <Window.Resources>
  <ContentPresenter Content="{Binding CurrentView}"/>
</Window>

如果
Window.DataContext
ViewModelA
的实例,则将显示
ViewA
,并且
Window.DataContext
ViewModelB
的实例,然后将显示
ViewB


我所见过和读过的最好的例子是瑞秋·林

在某些情况下,我们必须以模型或非模型对话框的形式启动视图。为了保持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();
    }
}

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

在MVC上下文中,模型中的命令看起来很奇怪。您的意思是什么?这是wpf?您需要正确注册服务。看看BookingView的类型是什么?BookingView实现了一个空接口,BookingViewModel也实现了这个接口。已经添加了BookingView类。感谢您的快速回复,我会看看这个。容器字段,您从哪里得到的?这只是我展示的演示代码。你可以从应用程序中公开UnityContainer,并在任何你喜欢的地方使用它。我不太明白你的意思。。看看我的更新。我想我现在已经正确注册了类型。现在DialogService中不存在唯一的容器。。有什么提示吗?您可以在App类中为容器创建公共属性,然后在整个应用程序中使用它
    public IUnityContainer _container;
    public IUnityContainer UnityContainer
    {
        get
        {
            if (_container == null)
            {
              _container = new UnityContainer();

            }
            return _container;
        }
    }