我对ASP.NET Core以及开箱即用的依赖注入支持非常熟悉。控制器可以通过在构造函数中添加参数来请求依赖项。但是,如何在WPF UserControls中实现依赖项呢?我尝试向构造函数添加参数,但这并没有起作用。我喜欢IOC的概念,并希望将其引入到WPF中。
我对ASP.NET Core以及开箱即用的依赖注入支持非常熟悉。控制器可以通过在构造函数中添加参数来请求依赖项。但是,如何在WPF UserControls中实现依赖项呢?我尝试向构造函数添加参数,但这并没有起作用。我喜欢IOC的概念,并希望将其引入到WPF中。
Microsoft.Extensions.DependencyInjection
private readonly ServiceProvider _serviceProvider;
public App()
{
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
_serviceProvider = serviceCollection.BuildServiceProvider();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ILogBase>(new LogBase(new FileInfo($@"C:\temp\log.txt")));
services.AddSingleton<MainWindow>();
}
private void OnStartup(object sender, StartupEventArgs e)
{
var mainWindow = _serviceProvider.GetService<MainWindow>();
mainWindow.Show();
}
<Application x:Class="VaultDataStore.Wpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VaultDataStore.Wpf"
Startup="OnStartup">
<Application.Resources>
</Application.Resources>
</Application>
private readonly ILogBase _log;
public MainWindow(ILogBase log)
{
_log = log;
...etc.. you can use _log over all in this class
maytham-ɯɐɥʇʎɐɯ的回答中提到,从"App"类和"Startup"方法配置依赖注入是好的,但我实现的IServiceProvider作为属性需要改进。
public IServiceProvider ServiceProvider { get; private set; }
public class ViewModelProvider : MarkupExtension
{
#region ctor
public ViewModelProvider()
{
}
public ViewModelProvider(Type viewModelType)
{
ViewModelType = viewModelType;
}
#endregion ctor
#region properties
public Type ViewModelType { get; set; }
#endregion properties
#region methods
public override object ProvideValue(IServiceProvider serviceProvider)
{
return ((App)Application.Current).ServiceProvider.GetService(ViewModelType);
}
#endregion methods
}
然后在XAML中,您可以向ViewModelProvider请求要使用的ViewModel类型
DataContext="{local:ViewModelProvider local:MainViewModel}"
这是一个好问题,如果在XAML中没有非参数化构造函数,就不能有控件。如果你需要,你可以从代码中实例化它,但XAML不会调用该构造函数。
"Original Answer"翻译成中文是"最初的回答"。
container.Resolve<IMainViewModel>()
。自从DI变得流行以来,WPF并没有得到很多维护。 - Robert Jørgensgaard Engdahl<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:MyMvvmProject.ViewModel" />
</ResourceDictionary>
</Application.Resources>
Windows和用户控件是可绑定应用程序资源的视觉树的一部分,因此在该框架中,主窗口通常会这样绑定到视图模型:
<Window x:Class="MyMvvmProject.MainWindow"
...
DataContext="{Binding Source={StaticResource Locator}, Path=Main}">
...其中 Main
是定位器类的一个属性:
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
ServiceProvider
放入 ViewModelLocator
(我称其为 ApplicationKernel,因为我使用 Ninject 的时间)中,然后你就完成了。应用程序可以在需要在代码背后使用资源时从中检索它。 - Orace