2010-04-30 278 views
5

我们使用Microsoft Unity和依赖注入,因此我们拥有参数化的usercontrol构造函数。如何使用XAML将此依赖注入到usercontrol?带参数化构造函数的Wpf用户控件

我已经在XAML中添加了usercontrol,如下所示。

xmlns:usrRefundArrivalProcessor="Ttl.Refunds.Wpf.Dashboad.Application.Usercontrols;assembly=Ttl.Refunds.Wpf.Dashboad.Application" 

回答

10

依赖注入并不意味着参数化的构造函数。实际上,如果您查看Unity附带的示例,大多数依赖注入都是通过具有[Dependency]属性的属性完成的。

Unity对XAML非常适用,但前提是您不使用参数化构造函数。将UserControl转换为使用带有[Dependency]属性的属性的依赖关系,并且可以轻松使用XAML。

public class MyUserControl : UserControl 
{ 
    [Dependency] 
    public ISomething Something { get; set; } 

    [Dependency] 
    public IWhatever Whatever { get { return (IWhatever)GetValue(WhateverProperty); } set { SetValue(WhateverProperty, value); } 
    public readonly DependencyProperty WhateverProperty = DependencyProperty.Register("Whatever", typeof(IWhatever), typeof(MyUserControl)); 

    ... 
} 

。注意,[依赖]属性可以被声明为一个DependencyProperty或纯CLR属性,如上所示。这听起来像命名混淆,但实际上它非常简单。

要指定XAML的UnityContainer并获得自动配置,只需要创建一个继承附加属性“UnityHelper.Container”,其PropertyChangedCallback简单地调用指定的容器上积聚并通过在对象的类型和对象:

public class UnityHelper 
{ 
    public static IUnityContainer GetContainer(DependencyObject obj) { return (IUnityContainer)obj.GetValue(ContainerProperty); } 
    public static void SetContainer(DependencyObject obj, IUnityContainer value) { obj.SetValue(ContainerProperty, value); } 
    public static readonly DependencyProperty ContainerProperty = DependencyProperty.RegisterAttached("Container", typeof(IUnityContainer), typeof(UnityHelper), new FrameworkPropertyMetadata 
    { 
    Inherits = true, 
    PropertyChangedCallback = (obj, e) => 
    { 
     var container = e.NewValue as IUnityContainer; 
     if(container!=null) 
     { 
     var element = obj as FrameworkElement; 
     container.BuildUp(obj.GetType(), obj, element==null ? null : element.Name); 
     } 
    } 
    }); 
} 

现在你可以指定一个UnityContainer到你的根窗口,整个应用程序将使用它,举例如下,你可以做你的窗口的构造函数:

UnityHelper.SetContainer(this, new UnityContainer() ...); 

或者你可以分配使用XAML在树的任何所需水平的统一容器:

<UserControl ... 
    my:UnityHelper.Container="{DynamicResource MainUnityContainer}" /> 

说了这么多,我想你会会发现WPF先进的数据绑定功能和资源字典一起消灭的原因,98%为什么人可能想要首先使用Unity。从长远来看,您可能会发现离开Unity并使用简单的MVVM更好。至少我会尝试在测试应用程序上使用纯MVVM,以便在开发依赖Unity进行依赖注入的大量代码之前查看它是如何工作的。

+0

它的工作原理,但是当我从其中一个文本框中打开标签按钮时,它会抛出异常 解析依赖失败,type =“System.Windows.Input.KeyboardNavigation + FocusVisualAdorner”,name =“”。异常消息是:当前的构建操作(构建键构建键[System.Windows.Input.KeyboardNavigation + FocusVisualAdorner,null])失败:无法从程序集'PresentationFramework,Version = 3.0中加载类型'System.Windows.Input.KeyboardNavigation' .0.0,Culture = neutral,PublicKeyToken = 31bf3856ad364e35'。 (策略类型BuildPlanStrategy,索引5) – Miral 2010-05-24 14:09:31

+0

这个答案帮了我很大的忙。我希望我可以给+1。我已经将此线程添加到“我的收藏夹”中,但只是将这个问题归功于提出原始问题的人。所以谢谢! – Tormod 2011-03-02 09:05:27

+0

如果您创建一个接口(称为IUnityElement),并将其应用于所有UserControl或控件,则需要在'if(container!= null)'行中运行,然后在该行中运行,则可以检查obj参数是否为该接口例如'if(container!= null && obj is IUnityInject)'。这消除了Miral上面评论的错误(我从一个不同的对象中得到了类似的结果,ZeePrime的回答也是性能问题,因为BuildUp只能在您需要的FrameworkElements上运行。 – 2011-11-05 23:28:46

0

看起来相当容易。为什么不简单地在您的UserControl中添加“公共无参数构造函数”?你可以选择不直接在你的代码中使用它,但这正是设计师正在寻找的。如果你想确保它永远不会在代码中被调用,那么把a check for presence of Designer放进去,如果没有检测到Designer,就会抛出一个异常。

0

它可以工作,但是当您使用网格或复杂的WPF屏幕时,性能非常糟糕。 Inherits = true意味着创建的所有GUI元素都将在构造函数之后调用所附属性的PropertyChangedCallback,即使该特定GUI元素根本不需要Unity也是如此。 当你有网格时,每次出现一个新的行时,所有的GUI元素都会随着这个回调被调用而创建。 这是我们的网格性能的杀手,所以我们不得不通过这种方式去除UnityInjection。

但是仍然有一些地方我们需要在代码隐藏方面使用UnityInjection,即使我们使用MVVM,我们也没有找到这个问题的一个很好的解决方案。 一些复杂的用户控件是使用MVVM设计的,其中控件的ViewModel由控件自身的代码隐藏创建,由使用该控件的XAML创建。 在这个特定情况下,控件的ViewModel不知道任何有关Unity的内容,但是我们需要注入统一的注入,以便访问注册的外部资源。