当我有可交换的子部件时,为什么我需要使用无外观控件而不是UserControl

时间:2014-03-28 11:59:11

标签: wpf xaml

我有一个WPF应用程序,其中包含一些具有可交换子部件的自定义控件(在同一项目中定义)。作为一个基本的例子,让我说我有一些像Xaml:

<Border Background="White" CornerRadius="9">
    <ContentPresenter/>
</Border>

用于从ContentControl派生的班级,我们称之为MrWhiteControl

如果我使MrWhiteControl成为一个xaml和代码隐藏文件对(因此它在ctor中有一个InitializeComponent()调用),那么我在Content属性中放置的内容有很多问题,例如DataContext赢得了正确的继承权,并且在绑定中使用ElementName无法正常工作。

但是,如果我使用lookless control - 所以MrWhiteControl.cs文件具有在Themes / Generic.xaml中定义的样式(我不关心在这个应用程序中提供支持) - 那么一切正常细

我想知道的是为什么会这样。在幕后发生什么意味着无形控件工作得很好,但带有代码隐藏的xaml无法正常工作?

我创建了example project you can clone from GitHub。如果你运行它,你会发现ElementName绑定在具有代码隐藏(列表中的第2个)的控件内部不起作用,但是对于无外观控件可以正常工作(列表的底部)。

托管内容演示者的无外观和用户控件之间有什么区别?

1 个答案:

答案 0 :(得分:3)

修改:添加了一个解决方案,让绑定在底部使用此方法。


好问题。

AFAICT这只是因为设置DP的方式以及何时解析了关于NameScope的Binding。

MainWindow.xaml开始,您为控件分配DP MyContent属性,并使用代码隐藏,将整个TextBox代码作为DP值。因此,此时绑定尚未解决。

当应用Binding时,在UserControl的范围内,找不到ElementName,我们可以验证是否在TextBox中添加了另一个UserControl,比如说

<StackPanel>
  <TextBox Name="textBox" Text="Sampleeeeeeee" />
  <ContentPresenter Content="{Binding MyContent, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type LookslessVsUserControl:MrWhiteWithCodeBehind}}}" />
</StackPanel>

现在我们得到

enter image description here

作为解决Binding的点,新的TextBox是范围内的那个而不是来自MainWindow.xaml的那个

对于Style,范围在Style应用的位置保持不变,因此它会找到MainWindow.xaml的文本框。因此,我们只有一级嵌套,我们也可以从Snoop看到

enter image description here

<强>解决方案:

如果您喜欢使用控件设置DP,您仍然可以使Binding工作:

在您的MainWindow.xaml.cs中,您需要相应地为UserControl设置名称范围,以便它不会使用它自己的WPF Xaml NameScope

ctor() of MainWindow.xaml.cs

Loaded += (sender, args) => NameScope.SetNameScope(problemControl, NameScope.GetNameScope(this));

在xaml中我将其命名为problemControl,例如:

<LookslessVsUserControl:MrWhiteWithCodeBehind x:Name="problemControl">
  <LookslessVsUserControl:MrWhiteWithCodeBehind.MyContent>
    <TextBlock Text="{Binding ElementName=textBox, Path=Text}" />
  </LookslessVsUserControl:MrWhiteWithCodeBehind.MyContent>
</LookslessVsUserControl:MrWhiteWithCodeBehind>

UserControl加载并尝试解析Binding时,它会找到TextBox罚款,并为您提供所需的输出。