在WPF中,如何限制Panel中的子类型?

时间:2011-02-15 05:36:52

标签: wpf types panel add children

我们想要创建一个Canvas的子类,它只允许特定类型的子类(他们需要熟悉我们的子类,反之亦然。)也就是说,有没有办法强制小组只接受孩子某种类型(或类型)?

中号

2 个答案:

答案 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>()