在运行时动态创建(封装)子级的 WPF 元素
我想创建一个 WPF 元素,该元素在运行时完全控制其子元素 - 当其属性更改时添加和删除子 UI。有点像 ItemsControl 在修改 ItemsSource 属性时所做的事情,尽管在我的例子中只有一个子项。
这将是 MVVM 的视图容器——当您给它一个模型或视图模型时,它会神奇地创建正确的视图并将所有内容连接起来。我的视图容器不需要模板化(因为它创建用户定义的视图,这些视图是 UserControls 并具有自己的模板),并且我希望它尽可能封装。我可以通过从像 Grid 这样的东西下降,并在我自己的属性更改时添加子控件来轻松地做到这一点;但是 Grid 公开公开其子元素集合,并允许任何人添加和删除内容。
我应该从哪个 WPF 类继承以获得最大程度的封装,以及如何在运行时向其添加子元素?
根据我对文档的理解,我尝试使用 FrameworkElement 和 AddVisualChild,只是为了看看是否可以在运行时创建子控件。我不清楚 AddLogicalChild 是否是必要的,但我将其放入以防万一:
public class ViewContainer : FrameworkElement {
private TextBlock _child;
public ViewContainer() {
_child = new TextBlock { Text = "ViewContainer" };
AddLogicalChild(_child);
AddVisualChild(_child);
InvalidateMeasure();
}
public object Content { get; set; }
protected override Size ArrangeOverride(Size finalSize) {
_child.Arrange(new Rect(finalSize));
return finalSize;
}
protected override Size MeasureOverride(Size availableSize) {
_child.Measure(availableSize);
return _child.DesiredSize;
}
}
当我将 ViewContainer 放入窗口并运行它时,我希望看到一个 TextBlock 说“ViewContainer”。但相反,我只看到一个空白窗口。很明显我错过了一些东西。
如何修复上述代码,以便“子”控件确实在运行时出现,但不会暴露给其他人干扰(超出可以避免的范围)?
I want to create a WPF element that, at runtime, is in full control of its child elements -- adding and removing child UI when its properties change. Something a bit like what ItemsControl does when you modify its ItemsSource property, though in my case there'll only be one child.
This will be a view container for MVVM -- when you give it a Model or a ViewModel, it will magically create the correct View and wire everything up. There's no need for my view container to be templatable (since it creates user-defined views, which are UserControls and have their own templates), and I'd prefer that it encapsulate as much as possible. I could probably do this easily by descending from something like Grid, and adding child controls when my own properties change; but Grid publicly exposes its collection of child elements and lets anyone add and remove stuff.
Which WPF class should I descend from for maximum encapsulation, and how do I add child elements to it at runtime?
Based on my understanding of the docs, I tried using FrameworkElement and AddVisualChild, just to see if I could create child controls at runtime. I'm not clear on whether the AddLogicalChild is necessary, but I put it in just in case:
public class ViewContainer : FrameworkElement {
private TextBlock _child;
public ViewContainer() {
_child = new TextBlock { Text = "ViewContainer" };
AddLogicalChild(_child);
AddVisualChild(_child);
InvalidateMeasure();
}
public object Content { get; set; }
protected override Size ArrangeOverride(Size finalSize) {
_child.Arrange(new Rect(finalSize));
return finalSize;
}
protected override Size MeasureOverride(Size availableSize) {
_child.Measure(availableSize);
return _child.DesiredSize;
}
}
When I put a ViewContainer into a Window, and run this, I expect to see a TextBlock saying "ViewContainer". But instead, I just see a blank window. So obviously I'm missing something.
How can I fix the above code so that the "child" control does appear at runtime, but isn't exposed for others to mess with (any more than can be avoided)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
要回答您的具体问题,您还需要覆盖 GetVisualChild 和 VisualChildrenCount 属性使您的子元素能够显示。
To answer your specific question, you'll also need to override GetVisualChild and VisualChildrenCount properties to enable your child element to be displayed.
您是否考虑过利用 WPF 对隐式 DataTemplates 的支持?
我处理与您类似的需求的方法是使用
ContentControl
。我将Content
属性绑定到我的 ViewModel。然后,我确保在 ContentControl 上方树中某处引用的资源字典中,我为可能分配给 Content 属性的所有 ViewModel 类型定义了 DataTemplates。这样,WPF 就可以为我的 ViewModel 连接正确的视图。
Have you thought about taking advantage of WPF's support for implicit DataTemplates?
The way I have handled a requirement similar to yours is by using a
ContentControl
. I bind theContent
property to my ViewModel. I then make sure that in Resource Dictionaries referenced somewhere in the tree above the ContentControl I have DataTemplates defined for all the types of ViewModels that might be assigned to the Content Property.This way WPF takes care of wiring up the correct view for my ViewModel.