C# 在MVVM中启动视图作为对话框的依赖项注入
我需要一些关于如何在ViewModel中处理依赖项注入的建议。My viewModelC# 在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
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;
}
}