【问题标题】:Using Unity in WPF Custom Controls在 WPF 自定义控件中使用 Unity
【发布时间】:2010-10-13 13:28:03
【问题描述】:

我正在尝试创建一个 WPF 自定义控件,其中包含对已在 BootStrapper 中创建的统一容器的引用 - 例如

原因是我希望自定义控件能够解析统一容器,以便能够使用已注册到容器的一些服务。例如用户偏好服务/权利服务。

到目前为止,我已经创建了我的自定义控件,并在代码隐藏文件中包含了以下依赖属性

public static readonly DependencyProperty ContainerProperty = DependencyProperty.Register("Container", typeof(UnityContainer), typeof(SomeCustomWPFControl), new PropertyMetadata("DefaultTestValue"));

    public UnityContainer Container
    {
        get { return (UnityContainer)GetValue(ContainerProperty); }
        set { SetValue(ContainerProperty, value); }
    }

在我尝试包含自定义控件的 WPF 表单中,我已将以下行添加到资源区域:

<Unity:UnityContainer x:Key="unitContainer"></Unity:UnityContainer>

我尝试以它自己的形式创建自定义控件:

<Globe:SomeCustomWPFControl Container="{DynamicResource unitContainer}" DockPanel.Dock="Right" x:Name="JimEditor1" Grid.Column="0" Grid.Row="3"></Globe:SomeCustomWPFControl>

我在运行时收到的唯一错误信息是

标记文件“[程序集名称];[路径/文件].xaml”第 135 行位置 22 中的对象“System.Windows.Controls.Grid”出错。

关于我哪里出错了有什么建议吗?谢谢。

完整的 Xaml:

<UserControl x:Class="DB.GPF.Globe.Views.JimTestPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:Globe="clr-namespace:DB.GPF.Globe" 
xmlns:Unity="clr-namespace:Microsoft.Practices.Unity;assembly=Microsoft.Practices.Unity">
<UserControl.Resources>
    <Unity:UnityContainer x:Key="unitContainer"></Unity:UnityContainer>
</UserControl.Resources>
<Grid>
    <Globe:SomeCustomWPFControl Container="{DynamicResource unitContainer}" x:Name="JImTestControl1"></Globe:SomeCustomWPFControl>
</Grid>

更新:如果类型更改为内置 .Net 类型,则问题似乎是 UnityContainer 或 IUnityContainer 类型的 DependencyProperty,例如字符串然后它运行正常。任何想法为什么我们不能拥有 UnityContainer 或 IUnityContainer 类型的 DependencyProperty?

【问题讨论】:

  • 你能发布你的 Xaml 的其余部分吗?
  • 这是完整的 Xaml:

标签: c# wpf unity-container


【解决方案1】:

我认为,在自定义控件中嵌入 Unity 并不是一个好主意。

如果您需要更改自定义控件的某些属性,而不是公开这些属性并更改它们

【讨论】:

  • 这个想法是,在控件创建期间,它将使用服务来获取适用于该控件的首选项和权利。 IE。如果它以英国/美国格式显示日期,当前用户是否可以编辑该控件。等等……
  • 不能在代码中不嵌入统一性的情况下更改这些属性吗?为什么我这么说是因为如果你在你的控件中嵌入了统一,你的控件本身依赖于统一,如果将来你需要用其他 DI 提供者替换统一,而不是改变你的自定义控件,我认为这不是一个好建议,剩下的就是你的代码,你可以在里面做你想做的事情:)
  • saurabh 是对的。您不应该在代码中添加容器。我总是建议反对它。容器应该将对象和值注入到您的控件中。
  • 感谢您的回复,但我目前不明白您对此的反对意见。使用统一的想法是允许以真正的 IoC 风格更改我将来使用的服务实现。
  • @Jim 我相信反对意见的产生是因为您正在用对容器本身的依赖替换对给定服务实现的依赖。更好的做法是让您的自定义控件接受 IPreferenceServer,例如,并使用 Unity 容器 在控件之外 来解析 IPreferenceServer 实现 ,然后将服务注入控制。
【解决方案2】:
<Globe:SomeCustomWPFControlContainer="{DynamicResource unitContainer}" DockPanel.Dock="Right" x:Name="JimEditor1" Grid.Column="0" Grid.Row="3"></Globe:SomeCustomWPFControlContainer>

&lt;Globe:SomeCustomWPFControlContainer 之后的 xaml 中有问题。您缺少要绑定的属性。

编辑:您的 get 值也是错误的。你有 GetValue(GetValue(ContextMenuProperty)) 它应该是......

public UnityContainer Container
{
    get { return (UnityContainer)GetValue(ContainerProperty); }
    set { SetValue(ContainerProperty, value); }
}

【讨论】:

  • 感谢您的快速回复,您当然是正确的,我已经在我的代码中更改了它,但它没有任何效果,因为我假设它在使用 getter 之前失败。我假设错误归结为运行时无法找到我的统一控制器,但无法弄清楚如何将其正确包含在资源区域中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多