【问题标题】:WPF element that dynamically creates (encapsulated) children at runtime在运行时动态创建(封装)子级的 WPF 元素
【发布时间】:2011-03-07 07:45:35
【问题描述】:

我想创建一个 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 放入 Window 并运行它时,我希望看到一个 TextBlock 显示“ViewContainer”。但相反,我只看到一个空白窗口。所以很明显我错过了一些东西。

我怎样才能修复上面的代码,以便“子”控件在运行时出现,但不会暴露给其他人乱七八糟(不能避免)?

【问题讨论】:

    标签: wpf encapsulation frameworkelement dynamic-ui


    【解决方案1】:

    要回答您的具体问题,您还需要覆盖 GetVisualChildVisualChildrenCount 属性以显示您的子元素。

    【讨论】:

    • 酷——做到了。虽然我有点困惑为什么有一个 AddVisualChild 如果它实际上没有添加它 to 任何东西。
    • 啊,我明白了。它让孩子了解它的父母;但是许多父母不需要孩子的清单(没有孩子或只有孩子),因此将存储的选择权和责任留给了父母。积极的关注点分离:我非常喜欢 WPF 的一件事。但这意味着“AddVisualChild”这个名称具有误导性,因为它表明它正在将其添加到某种列表中,而事实并非如此。
    【解决方案2】:

    您是否考虑过利用 WPF 对隐式 DataTemplates 的支持?

    我处理与您类似的要求的方式是使用ContentControl。我将Content 属性绑定到我的ViewModel。然后,我确保在 ContentControl 上方树中某处引用的资源字典中,我为所有可能分配给 Content 属性的 ViewModel 类型定义了 DataTemplates。

    这样,WPF 负责为我的 ViewModel 连接正确的视图。

    【讨论】:

    • 是的,我以前做过,但这次我想更进一步——我希望我的 ViewContainer 能够获取一个模型,并自动发现并创建正确的 ViewModel它,然后从那里到视图。我不认为 DataTemplate.DataType 会让我在没有帮助的情况下到达那里。
    • 当然,DataTemplate.DataType 不适合,但是有 DataTemplateSelector 可能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    相关资源
    最近更新 更多