在 WPF 中,如何限制面板中子项的类型?
我们想要创建一个 Canvas 的子类,它只允许特定类型的子类(他们需要对我们的子类有深入的了解,反之亦然。)也就是说,有没有办法强制面板只接受特定类型的子类类型(或类型)?
中号
We want to create a subclass of Canvas that only allows children of a specific type (they need to have intimate knowledge of our subclass and vice-versa.) That said, is there any way to force a panel to only accept children of a certain type (or types)?
M
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我们提出的解决方案是简单地对 Canvas 进行子类化,然后监视子级。如果添加的类型不是我们想要的类型,我们会立即将其删除并抛出错误。不会阻止编译时错误,但可以解决问题。
进一步扩展这一点,我正在考虑对画布进行子类化,然后对 Children 属性进行新建以返回我们自己的集合,我们已通过绑定在内部同步到面板的子级。这样我们也可以获得编译时支持。当然,如果有人将我们的子类转换为直接画布,那么显然“新的 Children 属性将不会被访问(它是“新的”而不是覆盖),但前面提到的集合监视仍然会给我们我们想要的东西。
如果 WPF 团队能够提出一个通用画布,这样我们就可以做类似画布的事情,那就太好了,但这显然在 XAML 中不起作用,除非他们以某种方式提出了相应的语法。话又说回来,画布是非常基本的,所以也许我们会推出自己的通用版本,我们可以做这样的事情...
...然后我们可以通过以下方式使用 FooCanvas 和 LaaCanvas XAML 同时仍然获得使用泛型的所有好处。
更好的是,将其设置为 TypedPanelBase,这样我们就可以将它与任何其他自定义面板一起用作基本类型。
事实上,现在我已经输入了这个......我想我即将重新编写我们的画布来尝试这种方法! (无论如何,我现在有了一个解决方案,这就是我们所追求的。)
The solution we came up with was to simply subclass the Canvas, then monitor the children. If one is added that's not of the type we want, we instantly remove it and throw an error. Won't stop compile-time errors but does the trick.
Extending this further I was thinking about also subclassing the canvas, then Newing over the Children property to return our own collection which we've internally synced to the panel's children via binding. That way we can also have compile-time support. Granted if someone casts our subclass to a straight canvas, then obviously the 'new'd Children property won't be accessed (its a 'new' not an override) but the aforementioned collection monitoring will still give us what we want.
It would have been nice if the WPF team had come up with a generic canvas so we could do something like canvas but that obviously wouldn't work in XAML unless they somehow came up with syntax for that. Then again, a canvas is pretty damn basic so maybe we'll just roll our own geeneric version where we could do something like this...
...of which we could then use FooCanvas and LaaCanvas via XAML while still getting all the benefits of using generics.
Even better, make it TypedPanelBase so we could use it with any other custom panel as the base type.
Actually, now that I've typed this... I think I'm about to go re-write our canvas to try this approach! (Either way, I now have a solution which is what we were after.)
其实……没办法。
另外,我不明白你的目标。如果您需要使用某些特定容器,只需转换 Panel.InternalChildren:
考虑一下场景:您有一个字符串集合,它是 ItemsControl 的源。在 DataTemplate 中,我们有一个按钮,该按钮将内容绑定到提到的集合中的项目。而 ItemsControl.ItemsPanel 是 Canvas。
那么,您想要限制哪些项目类型?按钮还是绳子?
这种情况下的问题是 ContentPresenters 将是 Canvas 的有效视觉子代。但在重写方法 OnVisualChildrenChanged (您可以尝试检查项目类型)中,由于延迟绑定,Content 和 ContentTemplate 属性被设置为 null。
因此,我可以建议的一个可接受的解决方案是创建您自己的 ItemsControl,它返回一些具体容器而不是 ContentPresenter:
通过这种方法,您可以保证您的项目容器(Panel.InternalChilder)是按钮(或其他东西),并且在 MyPanel 中您可以安全地投掷:
Actually... no way.
Besides, I don't understand your goals. If you need to work with some specific containers just cast Panel.InternalChildren:
Consider about scenario: you have a collection of strings, which is the source for ItemsControl. In DataTemplate we have button which content is binded to item from mentioned collection. And ItemsControl.ItemsPanel is Canvas.
So, what items types do you want to restrict? Buttons or strings?
The problem in this scenario is that ContentPresenters will be effective visual children of Canvas. But in overriden method OnVisualChildrenChanged (where you could try to check item type) Content and ContentTemplate properties are set to null due to deferred binding.
So the one acceptable solution I can propose is creating your own ItemsControl, which returns some concrete container instead of ContentPresenter:
With this approach, you guarantee that your item containers (Panel.InternalChilder) are buttons (or something) and in MyPanel you could safely cast: