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)
在某些情况下,我们必须将视图作为模型或无模式对话框启动。为了将事物保持在 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)
这样做将有助于保持虚拟机的可测试性,因为您也可以通过测试注入服务的模拟。