用过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)
{
//...省略
}
}