Xamarin Forms中如何为XAML元素创建带参数的构造函数?
问题解决方案
核心结论
XAML解析器默认仅支持调用无参构造函数实例化元素,无法直接通过依赖注入创建带参数构造的XAML元素,但可以通过以下几种方式为Behavior注入依赖服务,实现简洁的XAML写法:
1. 自定义可注入Behavior基类
创建一个基类,在无参构造中直接从DI容器解析所需服务,派生Behavior直接继承即可使用:
// 假设你的DI容器通过App.Current.Services访问 public abstract class InjectableBehavior<T> : Behavior<T> where T : BindableObject { protected IMyRequiredService MyService { get; } protected InjectableBehavior() { MyService = App.Current.Services.GetService<IMyRequiredService>(); } } // 你的业务Behavior public class SomeBehavior : InjectableBehavior<Entry> { protected override void OnAttachedTo(Entry bindable) { base.OnAttachedTo(bindable); // 直接使用MyService处理业务逻辑 MyService.DoSomething(); } }
此时XAML中只需写:<SomeBehavior/>,依赖服务会在基类构造时自动注入。
2. 利用附加属性实现注入
创建静态附加属性,在属性变更回调中为Behavior注入服务:
public static class BehaviorInjector { public static readonly BindableProperty InjectServiceProperty = BindableProperty.CreateAttached("InjectService", typeof(Type), typeof(BehaviorInjector), null, propertyChanged: OnInjectServiceChanged); public static Type GetInjectService(BindableObject obj) { return (Type)obj.GetValue(InjectServiceProperty); } public static void SetInjectService(BindableObject obj, Type value) { obj.SetValue(InjectServiceProperty, value); } private static void OnInjectServiceChanged(BindableObject bindable, object oldValue, object newValue) { if (bindable is SomeBehavior behavior && newValue is Type serviceType) { var service = App.Current.Services.GetService(serviceType); behavior.MyService = (IMyRequiredService)service; } } }
XAML写法:
<SomeBehavior local:BehaviorInjector.InjectService="{x:Type local:IMyRequiredService}"/>
如果需要注入多个服务,可以扩展附加属性,或者给Behavior添加特性标记需要注入的服务类型,在附加属性中自动扫描注入,进一步简化XAML。
3. 自定义标记扩展解析服务
创建标记扩展,在XAML中直接解析DI服务并赋值给Behavior的属性:
public class ResolveServiceExtension : IMarkupExtension { public Type ServiceType { get; set; } public object ProvideValue(IServiceProvider serviceProvider) { return App.Current.Services.GetService(ServiceType); } }
假设Behavior定义了依赖属性MyService:
public class SomeBehavior : Behavior<Entry> { public static readonly BindableProperty MyServiceProperty = BindableProperty.Create(nameof(MyService), typeof(IMyRequiredService), typeof(SomeBehavior), null); public IMyRequiredService MyService { get => (IMyRequiredService)GetValue(MyServiceProperty); set => SetValue(MyServiceProperty, value); } }
XAML写法:
<SomeBehavior MyService="{local:ResolveService ServiceType={x:Type local:IMyRequiredService}}"/>
如果觉得属性名冗长,可以在标记扩展中预设常用服务类型,或者通过泛型实现更简洁的写法。
关于DependencyResolver.ResolveUsing的说明
你提到的DependencyResolver.ResolveUsing确实仅针对渲染器、效果这类框架级特殊组件设计,无法用于Behavior这类自定义元素的依赖注入,因此不适用你的场景。
对比绑定ViewModel属性的方式,上述方法无需依赖ViewModel,能保持Behavior的独立性,同时避免冗长的XAML代码。
内容的提问来源于stack exchange,提问作者raV720
相关产品推荐
相关产品推荐

