In WPF how can I restrict the type of children in a Panel?
我们想创建一个Canvas子类,该子类仅允许特定类型的子类(他们需要对我们的子类有深入的了解,反之亦然。)也就是说,有什么方法可以强制面板仅接受子类?某种类型(或几种)的类型?
M
我们想出的解决方案是简单地将Canvas子类化,然后监视孩子。如果添加的不是我们想要的类型,我们会立即将其删除并抛出错误。不会停止编译时错误,但是可以解决问题。
进一步扩展我的想法是,我还考虑了画布的子类化,然后是Children属性的Newing以返回我们自己的集合,我们已通过绑定将其内部同步到面板的子代。这样,我们还可以获得编译时支持。如果有人将我们的子类转换为纯画布,则很显然,'new'd Children属性将不会被访问(它是一个'new',而不是替代项),但是前面提到的集合监视仍将提供我们想要的东西。 >
如果WPF团队提出了一个通用画布,那就太好了,所以我们可以做画布之类的事情,但是除非他们以某种方式提出了语法,否则在XAML中这显然是行不通的。再说一遍,画布是非常不可思议的基础,所以也许我们只需要滚动我们自己的geeneric版本,就可以做这样的事情...
1 2 3 4 5 6 7 | public class TypedCanvas< T > : PanelBase { // Implementation here } public class FooCanvas : TypedCanvas<Foo>{} public class LaaCanvas : TypedCanvas<Laa>{} |
...然后我们可以通过XAML使用FooCanvas和LaaCanvas,同时仍然获得使用泛型的所有好处。
更好的是,将其设置为TypedPanelBase,以便我们可以将其与其他任何自定义面板一起用作基本类型。
实际上,现在我已经输入了这个……我想我将重新编写画布以尝试这种方法! (无论哪种方式,我现在都有一个解决方案,这正是我们所追求的。)
实际上...没办法。
此外,我不了解您的目标。如果您需要使用某些特定的容器,则只需转换Panel.InternalChildren:
1 | this.InternalChildren.OfType<MyType>().Do(...); |
考虑场景:您有一个字符串集合,这是ItemsControl的源。在DataTemplate中,我们有一个按钮,该按钮将内容绑定到提到的集合中的项目。而且ItemsControl.ItemsPanel是Canvas。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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中可以安全地投射:
1 | this.InternalChildren.Cast<Button>() |