我有一个UWP-App,我在其中创建了一个模板控件' Bracket'它包含一个声明如下的DependencyProperty:
public ObservableCollection<BaseControl> Content
{
get { return (ObservableCollection<BaseControl>)GetValue(ContentProperty); }
set
{
SetValue(ContentProperty, value);
addChildren();
}
}
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content), typeof(ObservableCollection<BaseControl>),
typeof(Bracket), new PropertyMetadata(new ObservableCollection<BaseControl>()));
在XAML中使用像这样的控件时,一切正常:
<Math:Bracket>
<Math:Bracket.Content>
<Math:TextBlock Text="4" />
<Math:TextBlock Text="x" />
</Math:Bracket.Content>
</Math:Bracket>
(注意:两个类&#39; Bracket&#39;&#39; TextBlock&#39;都来自&#39; BaseControl&#39;)
但是,当我尝试在这样的支架中添加一个支架时:
<Math:Bracket>
<Math:Bracket>
<Math:Bracket.Content>
<Math:TextBlock Text="4" />
<Math:TextBlock Text="x" />
</Math:Bracket.Content>
</Math:Bracket>
</Math:Bracket>
我得到一个例外:&#39;元素已经是另一个元素的孩子&#39;
经过一些调试后我发现,在两个Bracket对象的每一个中,属性Content 包含3个元素:TextBlocks和内部Bracket。
我期望和我想要的是,外部支架的内容仅包含内部支架,内部支架的内容仅包含两个文本块。
自小组以来,例如。一个StackPanel有一个非常相似的函数(它包含子节点,其中一个子节点也可以是StackPanel类型)所以我查找了Panel类的代码。但是,似乎使用了IAddChild接口
在msdn文档(https://msdn.microsoft.com/de-de/library/system.windows.markup.iaddchild(v=vs.110).aspx)中,据说这是过时的,并且&#34; Collection行为现在是XAML类型系统的一部分&#34;。因此我使用了一个集合,但它产生了不同的结果
我该如何解决这个问题?或者我应该使用不同的方法来实现此功能(可能使用IAddChild接口?
答案 0 :(得分:0)
对于每个控件实例,此属性的每个实例的默认值是相同的ObservableCollection :
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content), typeof(ObservableCollection<BaseControl>),
typeof(Bracket), new PropertyMetadata(new ObservableCollection<BaseControl>()));
对于每个实例,XAML解析器/将其子项添加到其Content
。但它总是相同的集合!所以第一个得到它的孩子,这导致第二个得到那些孩子。然后它添加了第二个孩子的孩子,并且他们两个都引用了同一个集合。
您不能为PrpertyMetadata
提供引用类型的默认非空值,除非它像System.String
这样是不可变的。您可以共享相同的字符串值。
使用null
作为默认值,并在构造函数中使用新集合进行初始化,因此Bracket
的每个实例都有自己的子集合。
public Bracket()
{
Content = new ObservableCollection<BaseControl>();
}
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content), typeof(ObservableCollection<BaseControl>),
typeof(Bracket), new PropertyMetadata(null));
顺便说一句,你的setter中的addChildren();
看起来非常可疑,但是setter可能永远不会被调用。 XAML不会打电话给它。框架直接调用DependencyObject.SetValue()
。放入断点看看。除非您自己的代码想要将该传统Content
属性与get和set一起使用,否则这是惯例,但并非严格必要。鉴于该属性通常会设置而不触及该setter ,但是,您永远不应该在其中添加任何额外的代码。属性值更改时应该发生的任何事情都应该在依赖项属性的PropertyChanged
处理程序中完成。