2017-04-18 41 views
0

我有一個UWP-應用程序中,我創建了一個模板化控件「支架」,它包含一個DependencyProperty聲明如下:在XAML中設置的類型ObservableCollection <T>的DependencyProperty包含的項目多於聲明的項目。 C#

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> 

(注:兩個類「支架」和「TextBlock的」從「BASECONTROL」派生)
但是當我試圖在這樣的托架添加一個支架:

<Math:Bracket> 
    <Math:Bracket> 
     <Math:Bracket.Content> 
      <Math:TextBlock Text="4" /> 
      <Math:TextBlock Text="x" /> 
     </Math:Bracket.Content> 
    </Math:Bracket> 
</Math:Bracket> 

我得到一個異常:「元素已經是另一個元素的子」
一些調試後我發現,在每兩個支架的對象的屬性內容包含3個元素:兩個的TextBlocks和內托架。
我所期望的和我想要的是,外部括號的內容僅包含內部括號,而內部括號的內容僅包含兩個TextBlocks。
由於面板例如。一個StackPanel有一個非常相似的功能(它包含了一個孩子也可以是StackPanel類型的子元素),所以我查找了Panel類的代碼。但是,似乎在那裏使用了IAddChild接口。
在msdn文檔(https://msdn.microsoft.com/de-de/library/system.windows.markup.iaddchild(v=vs.110).aspx)中說這已經過時,並且「收集行爲現在是XAML類型系統的一部分」。因此我使用了一個集合,但它產生了不同的結果。
我該如何解決這個問題?或者我應該使用不同的方法則是通過IAddChild接口來實現這個功能(

+1

什麼是'addChildren()',它在幹什麼?我不認爲它應該在那裏。 –

+0

addChildren()將一些其他UIControls(不是Content中的那些)添加到Control(呈現內容的開始和結束括號) – Hannes

回答

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)); 

順便說一句,addChildren();在你的setter看起來很可疑,但二傳手可能永遠不會被調用。 XAML不會調用它。該框架直接調用DependencyObject.SetValue()。放置一個斷點,看看。除非你自己的代碼想要使用傳統的Content屬性來獲取和設置,否則這是習慣性的,但不是絕對必要的。鑑於該物業經常會被設置爲而不觸及該設置器,但是,您永遠不應該在其中放置任何額外的代碼。在屬性值更改時應該發生的任何事情都應在依賴項屬性的PropertyChanged處理程序中完成。

相關問題