我们想要创建一个Canvas的子类,它只允许特定类型的子类(他们需要熟悉我们的子类,反之亦然。)也就是说,有没有办法强制小组只接受孩子某种类型(或类型)?
中号
答案 0 :(得分:2)
我们提出的解决方案是简单地继承Canvas,然后监控孩子们。如果添加的不是我们想要的类型,我们会立即将其删除并抛出错误。不会停止编译时错误,但可以解决问题。
进一步扩展这一点我正在考虑对canvas进行子类化,然后对Children属性进行Newing以返回我们自己的集合,我们已通过绑定在内部同步到面板的子节点。这样我们也可以获得编译时支持。如果有人将我们的子类强制转换为直接画布,那么显然不会访问'new'd Children属性(它是'new'而不是覆盖),但前面提到的集合监视仍然会给我们想要的东西。
如果WPF团队提出了一个通用画布, 会很好,所以我们可以做类似画布的东西,但显然不会在XAML中工作,除非他们以某种方式提出了语法那。然后,画布非常基本,所以也许我们只是推出我们自己的geeneric版本,我们可以做这样的事情......
public class TypedCanvas<t> : PanelBase
{
// Implementation here
}
public class FooCanvas : TypedCanvas<Foo>{}
public class LaaCanvas : TypedCanvas<Laa>{}
...我们可以然后通过XAML使用FooCanvas和LaaCanvas,同时仍然可以获得使用泛型的所有好处。
更好的是,将其设为TypedPanelBase,以便我们可以将它与任何其他自定义面板一起用作基本类型。
实际上,现在我输入了这个......我想我将重新编写我们的画布来尝试这种方法! (无论哪种方式,我现在都有一个我们追求的解决方案。)
答案 1 :(得分:0)
其实......没办法。
此外,我不明白你的目标。如果你需要使用一些特定的容器,只需转换Panel.InternalChildren:
this.InternalChildren.OfType<MyType>().Do(...);
考虑一下场景:你有一个字符串集合,它是ItemsControl的源代码。在DataTemplate中,我们有一个按钮,其内容绑定到来自上述集合的项目。而ItemsControl.ItemsPanel是Canvas。
public IEnumerable<string> Items
{
get;
}
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
那么,您想要限制哪些项目类型?按钮或字符串? 这种情况下的问题是ContentPresenters将是Canvas的有效视觉孩子。但是在重写方法OnVisualChildrenChanged(您可以尝试检查项类型)中,由于延迟绑定,Content和ContentTemplate属性设置为null。
所以我建议的一个可接受的解决方案是创建自己的ItemsControl,它返回一些具体的容器而不是ContentPresenter:
public class MyItemsControl : ItemsControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new Button();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is Button;
}
}
<self:MyItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<self:MyPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</self:MyItemsControl>
使用这种方法,您可以保证您的项目容器(Panel.InternalChilder)是按钮(或其他东西),并且在MyPanel中可以安全地投射:
this.InternalChildren.Cast<Button>()