基于DI的.NET 5 WPF应用中UserControl的RoutedCommand如何访问注册服务
可行实现方案
以下是无需第三方框架的3种落地方案,按实现复杂度从低到高排序:
方案1:全局暴露IServiceProvider直接获取(最简单)
你可以在WPF应用的入口App.xaml.cs中将DI容器构建后的IServiceProvider存为公共静态属性,在UserControl的RoutedCommand逻辑中直接读取即可:
- 配置App的DI容器
public partial class App : Application { // 全局可访问的服务提供器 public static IServiceProvider ServiceProvider { get; private set; } protected override void OnStartup(StartupEventArgs e) { var services = new ServiceCollection(); // 注册你的所有服务,示例: services.AddSingleton<IMyBusinessService, MyBusinessService>(); services.AddScoped<IMyScopedService, MyScopedService>(); ServiceProvider = services.BuildServiceProvider(); base.OnStartup(e); } }
- 在UserControl的RoutedCommand逻辑中获取服务
public partial class MyListSubControl : UserControl { public static readonly RoutedCommand CustomOperationCommand = new RoutedCommand(); public MyListSubControl() { InitializeComponent(); CommandBindings.Add(new CommandBinding(CustomOperationCommand, OnCustomOperation)); } private void OnCustomOperation(object sender, ExecutedRoutedEventArgs e) { // 获取单例/ transient服务直接调用 var singletonService = App.ServiceProvider.GetRequiredService<IMyBusinessService>(); singletonService.ExecuteLogic(); // *如果是Scoped生命周期服务,需要先创建作用域避免内存泄漏 using var scope = App.ServiceProvider.CreateScope(); var scopedService = scope.ServiceProvider.GetRequiredService<IMyScopedService>(); scopedService.ExecuteScopedLogic(); } }
方案2:附加属性继承注入(符合DI规范,无全局变量)
如果不想使用全局静态属性,可以利用WPF依赖属性的继承特性,从上层可注入的控件(比如ListBox所在的父页面)向下传递服务实例:
- 定义继承的附加属性
public static class ServiceInjectionAttachedProperty { public static readonly DependencyProperty BusinessServiceProperty = DependencyProperty.RegisterAttached( "BusinessService", typeof(IMyBusinessService), typeof(ServiceInjectionAttachedProperty), // 开启属性继承,子控件自动获取父级设置的值 new FrameworkPropertyMetadata(FrameworkPropertyMetadataOptions.Inherits)); public static void SetBusinessService(DependencyObject element, IMyBusinessService value) => element.SetValue(BusinessServiceProperty, value); public static IMyBusinessService GetBusinessService(DependencyObject element) => (IMyBusinessService)element.GetValue(BusinessServiceProperty); }
- 在上层ListBox赋值服务,父页面的ViewModel/后台代码可以正常注入服务后绑定到附加属性:
<!-- 父页面的ListBox,通过绑定给附加属性赋值 --> <ListBox local:ServiceInjectionAttachedProperty.BusinessService="{Binding InjectedServiceInstance}"> <ListBox.ItemTemplate> <DataTemplate> <!-- 自动生成的子UserControl会继承附加属性的值 --> <local:MyListSubControl /> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
- UserControl中直接读取附加属性值使用
private void OnCustomOperation(object sender, ExecutedRoutedEventArgs e) { var service = ServiceInjectionAttachedProperty.GetBusinessService(this); service.ExecuteLogic(); }
方案3:自定义ItemContainer创建逻辑(适合多服务注入场景)
如果子UserControl需要注入多个服务,可以重写ListBox的子项生成逻辑,从DI容器直接解析UserControl实例,替代默认无参构造的实例化逻辑,复杂度略高,适合复杂场景。
内容的提问来源于stack exchange,提问作者Angelo
相关产品推荐
相关产品推荐

