首页 > 解决方案 > 您如何以编程方式在自定义 WPF 面板实现中创建新控件?

问题描述

我正在创建一个OverflowPanel派生自 WPFPanel类。意图是它会在一个方向上填充项目,当显示的项目太多时,多余的项目将被移除并替换为另一个控件以保持溢出。想想网站的面包屑,或 Windows 文件资源管理器中的地址栏。这是一个 .Net Core 3/C# 8 项目。

我有一个部分可行的解决方案:我继承Panel并覆盖MeasureOverride()ArrangeOverride()获得我想要的行为。我现在的问题是获得一个按钮或其他控件来代替被删除的项目。

我最初的幼稚方法是创建一个Button代码并尝试测量/排列它。

public class OverflowPanel : Panel
{
    // First by itself, but I did also try to host this in a new UIElementCollection
    private readonly Button _overflowButton = new Button();

    public override Size MeasureOverride(Size availableSize)
    {
        ...
        _overflowButton.Measure(availableSize);
        // Do stuff with _overflowButton.DerivedSize.
        ...
    }

    // Also attempted to draw int in ArrangeOverride()
}

确实给了我非零的测量结果。(我在按钮中放了一些虚拟内容。)我的算法在屏幕上为我提供了按钮应该去的空间,但是那里没有呈现任何内容。

通过检查 Visual Studio 中的 Live Visual Tree,我还确认了没有简单的没有视觉样式的按钮被绘制。

我尝试制作一个UIElementCollection并将按钮添加到该按钮以查看它是否会将其添加到可视化树中,但这也不起作用。

我见过的大多数 Google/StackOverflow 结果都暗示了一些类似的东西this.Children.Add(_overflowButton),但是当托管在 ItemsControl 中时这不起作用,因为它会接管管理对象的集合并在你试图弄乱它时抛出异常。

在深入研究 and 的代码后PanelUIElementCollection我注意到 Panel 允许您覆盖

UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)

使用UIElemenetCollection. 我创建了一个PinningUIElementCollection来欺骗 WPF 渲染额外的元素。它存储额外的项目,然后在访问迭代器时将它们滑入。它还进行索引修改以访问额外的项目集合和自动生成的项目集合。

这实际上奏效了。我的按钮现在显示(尽管没有正确的样式,但这是一个单独的问题。)

然而,我对这种方法的问题是它似乎需要做很多工作。它似乎也容易出错:当它尝试使用数字索引并忘记破坏它时,我很容易错过,从而导致不可预测的结果。

在我的派生面板实现中,是否有一种更简单/更直接的方法来显示一个额外的按钮或其他一些任意控件,而这些控件只需要更少的圈数?

标签: c#wpf

解决方案


推荐阅读