我需要一些关于如何在我的 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();
}
它创建一个 BookingView
和 BookingViewModel
的实例。我正在尝试使用依赖项注入(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
依赖于 BookingView
和 BookingViewModel
。
我应该将其注入(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/