我熟悉WPF和MVVM模式。现在,我正在尝试在我的新WPF应用程序中使用Autofac实践依赖注入模式。我想知道如何将依赖项注入到MVVM视图模型类中。
如下所示的代码,我有一个根视图模型类MainViewModel,它可以在需要时创建其他视图模型(例如MonitorPageViewModel)实例。在MonitorPageViewModel中,它还需要在需要时创建其他子视图模型(例如MonitorDashboardViewModel)实例。所有这些视图模型可能具有多个依赖项(ILogger、IRepository<RawMessage>、IParsingService等)。
在我的先前的WPF项目中,没有使用任何IoC容器,当需要时我总是在父视图模型中new一个子视图模型,并使用ServiceLocator提供所需的服务。现在,我想找出更多的依赖注入方法来解决这个问题。
我得到了几种方法(在下面的代码中演示),但我对其中任何一种都不满意。
1.使用IoC容器获取响应来创建MainViewModel;并将IoC容器实例注入到MainViewModel中;然后,使用IoC容器实例来解析每个子视图模型构造函数所需的对象。如果子视图模型类需要解析其他类,则将IoC注入其中。[听起来像另一个ServiceLocator]。
2.将MainViewModel及其后代视图模型所需的所有服务注入并沿着视图模型链传递服务。在需要的地方new视图模型实例。[需要注入很多服务,并将它们向下传递]
我不想在这个项目中使用MVVM框架,如Caliburn.Micro。有没有一个简单而优雅的解决方案?
这里是带有替代构造函数的
如下所示的代码,我有一个根视图模型类MainViewModel,它可以在需要时创建其他视图模型(例如MonitorPageViewModel)实例。在MonitorPageViewModel中,它还需要在需要时创建其他子视图模型(例如MonitorDashboardViewModel)实例。所有这些视图模型可能具有多个依赖项(ILogger、IRepository<RawMessage>、IParsingService等)。
在我的先前的WPF项目中,没有使用任何IoC容器,当需要时我总是在父视图模型中new一个子视图模型,并使用ServiceLocator提供所需的服务。现在,我想找出更多的依赖注入方法来解决这个问题。
我得到了几种方法(在下面的代码中演示),但我对其中任何一种都不满意。
1.使用IoC容器获取响应来创建MainViewModel;并将IoC容器实例注入到MainViewModel中;然后,使用IoC容器实例来解析每个子视图模型构造函数所需的对象。如果子视图模型类需要解析其他类,则将IoC注入其中。[听起来像另一个ServiceLocator]。
2.将MainViewModel及其后代视图模型所需的所有服务注入并沿着视图模型链传递服务。在需要的地方new视图模型实例。[需要注入很多服务,并将它们向下传递]
我不想在这个项目中使用MVVM框架,如Caliburn.Micro。有没有一个简单而优雅的解决方案?
public interface ILogger
{
// ...
}
public interface IRepository<T>
{
// ...
}
public interface IStatisticsService
{
// ...
}
public class RawMessage
{
// ...
}
public class Device
{
// ...
}
public class Parser
{
// ...
}
public interface IParsingService
{
void Parse(Parser parser);
}
public class DockPaneViewModel : ViewModelBase
{
// ...
}
public class HomePageViewModel : DockPaneViewModel
{
public HomePageViewModel(ILogger logger)
{
// ...
}
}
public class MonitorDashboardViewModel : DockPaneViewModel
{
public MonitorDashboardViewModel(IStatisticsService statisticsService)
{
// ...
}
}
public class MonitorPageViewModel : DockPaneViewModel
{
public MonitorPageViewModel(ILogger logger, IRepository<RawMessage> repository,
IRepository<Parser> parserRepository, IParsingService parsingService)
{
// ...
}
public void CreateDashboard()
{
IStatisticsService statisticsService = ??; // how to resolve the service?
var dashBoardVm = new MonitorDashboardViewModel(statisticsService); // how to create this?
}
}
public class ResourceManagementViewModel : DockPaneViewModel
{
public ResourceManagementViewModel(ILogger logger, IRepository<Device> deviceRepository)
{
// ...
}
}
这里是带有替代构造函数的
MainViewModel
。public class MainViewModel : ViewModelBase
{
public ObservableCollection<DockPaneViewModel> DockPanes
{
get;
set;
} = new ObservableCollection<DockPaneViewModel>();
#region approach 1
// use the IOC container take the response to create MainViewModel;
// and inject the Ioc Container instance to MainViewModel;
// then, use the IOC container instance to resovle every thing the child view models need
private readonly ISomeIocContainer _ioc;
public MainViewModel(ISomeIocContainer ioc)
{
_ioc = ioc;
}
public void ResetPanes_1()
{
DockPanes.Clear();
DockPanes.Add(new HomePageViewModel(_ioc.Resolve<ILogger>())); // how to new child view model and how to provide the constructor parameters?
DockPanes.Add(new MonitorPageViewModel(_ioc.Resolve<ILogger>(),
_ioc.Resolve< IRepository<RawMessage>>(),
_ioc.Resolve<IRepository<Parser>>(),
_ioc.Resolve<IParsingService>())); // also need to inject ISomeIocContainer to MonitorDashboardViewModel for resolve IStatisticsService
DockPanes.Add(new ResourceManagementViewModel(_ioc.Resolve<ILogger>(),
_ioc.Resolve<IRepository<Device>>()));
// add other panes
}
#endregion
#region approach 2
// pasing all dependencies of MainViewModel and all descendant View Models in to MainViewModel,
// and pass dependencies along the ViewModel chain.
private readonly ILogger _logger;
private readonly IRepository<RawMessage> _repository;
private readonly IRepository<Parser> _parserRepository;
private readonly IRepository<Device> _deviceRepository;
private readonly IParsingService _parsingService;
private readonly IStatisticsService _statisticsService;
public MainViewModel(ILogger logger, IRepository<RawMessage> repository,
IRepository<Parser> parserRepository, IRepository<Device> deviceRepository,
IParsingService parsingService, IStatisticsService statisticsService)
{
_logger = logger;
_repository = repository;
_parserRepository = parserRepository;
_deviceRepository = deviceRepository;
_parsingService = parsingService;
_statisticsService = statisticsService;
}
public void ResetPanes_2()
{
DockPanes.Clear();
DockPanes.Add(new HomePageViewModel(_logger)); // how to new child view model and how to provide the constructor parameters?
DockPanes.Add(new MonitorPageViewModel(_logger, _repository, _parserRepository, _parsingService)); // also need pass statisticsService down
DockPanes.Add(new ResourceManagementViewModel(_logger, _deviceRepository));
// add other panes
}
#endregion
}