[XAML]ContentProperty集合属性
用过WPF的童鞋都知道,Panel或者ItemsControl之类的控件能够在XAML里直接为它们设置子项:
<Grid> <Label Content="1" /> <Label Content="2" /> <Label Content="3" /> </Grid> <ListBox> <Label Content="1" /> <Label Content="2" /> <Label Content="3" /> </ListBox>
Panel之类的控件,它们的子项都是在Children这个属性里。
ItemsControl之类的控件,则是在Items这个属性里。
那么它们在XAML里是怎么做到不需要用到类似如下的方法而直接对子项赋值呢?
<Grid> <Grid.Children> <Label Content="1" /> <Label Content="2" /> <Label Content="3" /> </Grid.Children> </Grid> <ListBox> <ListBox.Items> <Label Content="1" /> <Label Content="2" /> <Label Content="3" /> </ListBox.Items> </ListBox>
在Panel的代码里,有这样一部分代码:
[ContentProperty("Children")] public class Panel { public UIElementCollection Children { get; } }
这段代码里,ContentProperty是注明Children属性是作为Panel的子项集合属性。这样在XAML中,就可以省略掉Panel.Children而直接给Panel的子项赋值了。
相应的,在ItemsControl里也有这样的代码:
[ContentPropery("Items")] public class ItemsControl { public ItemCollection Items { get; } }
如果我们自己的类也要定义一个这样的东西,怎么办才好呢?
为类加上ContentProperty,然后设置一个集合属性。
根据MSDN上的说明,我们只需要在类里这样做:
[ContentProperty("Children")] public class Test { public List<string> Children { get; set; } }
这样呢,我们就可以直接在XAML里为Test设置string子项了。
有童鞋会发现,这里是带set的,为何之前的Panel和ItemsControl里是没有set的呢?
因为有时候,我们的Children是有特殊功能的,不能让XAML对Children属性进行赋值,只能让我们的类进行初始化。
在Panel里,Children是UIElementCollection,它附带的功能是每当你Add和Remove控件的时候,会自动的设置该控件的Parent等等之类的信息。
如果我们自己的类,在子项增删时需要调用其它代码,那么,我们就需要自己创建一个集合类。
根据MSDN上的说法,只要我们的集合类继承IList<>接口即可。
[ContentProperty(Children)] public class Test { public Test() { _Children = new TestCollection(); } private TestCollection _Children; public TestCollection Children { get { return _Children; } } } public class TestCollection : IList<string> { ///...省略 }
但是作者在实际测试的时候遇到了一个问题,无论如何XAML也不认可没有set的Children属性。
研究了好一阵后,发现只要把IList<string>改为Collection<string>就可以达到目的了。(当然实际使用的时候不是string)
[ContentProperty("Children")] public class Test { public Test() { _Children = new TestCollection(); } private TestCollection _Children; public TestCollection Children { get{ return _Children; } } } public class TestCollection : Collection<string> { protected override void ClearItems() { //...省略 } protected override void InsertItem(int index, UIElement item) { //...省略 } protected override void RemoveItem(int index) { //...省略 } protected override void SetItem(int index, UIElement item) { //...省略 } }