WPF,基于(装饰器类)的自定义控件,装饰器的子级的垂直或水平对齐方式设置后生效

问题描述 投票:0回答:1

我想要一个自定义控件,它包围它的子控件并添加四个 FrameworkElements 作为(边框边),所以我选择了 WPF 的装饰器类,该类和 xaml 都在以下 github gist 中。 装饰器 测量和排列符合预期,但即使设置了对齐方式,子项也始终以装饰器为中心。

我尝试了很多东西,但它们要么破坏了安排/测量,要么根本不起作用,所以也许我对 MeasureOverride 和 ArrangeOverride 或 ??? 的理解存在根本问题。 我希望这个装饰器的功能类似于 Border 类,但具有 FrameworkElements 作为边框。

c# wpf xaml custom-controls
1个回答
0
投票

在 WPF 中扩展像

Decorator
这样的类时,了解
MeasureOverride
ArrangeOverride
的工作原理至关重要,因为它们分别决定子元素的大小和位置。在您的实现中,您已经重写了这两种方法,这是正确的,但是您处理子
FrameworkElement
的对齐和排列的方式可能没有考虑
HorizontalAlignment
VerticalAlignment
属性。

为了使您的

BorderWrapper
尊重子级的
HorizontalAlignment
VerticalAlignment
属性(如标准
Border
类所做的那样),您需要调整将子级放置在
ArrangeOverride
方法中的方式。在为“边框”分配空间后,
ArrangeOverride
应考虑子项相对于可用空间的对齐方式。

这是

ArrangeOverride
代码片段的调整版本,旨在尊重子项的对齐属性:

// The default size & the boundaries of an object
protected override Size ArrangeOverride(Size arrangeSize)
{
    // ... (previous code remains the same)

    // Calculate the top-left point where the Child should be arranged, taking alignment into account
    double childLeft = Left != null ? Left.DesiredSize.Width : 0;
    double childTop = Top != null ? Top.DesiredSize.Height : 0;

    // Determine the child's final alignment within the available space
    childLeft += child.HorizontalAlignment switch
    {
        HorizontalAlignment.Center => (childArrangeSize.Width - childDesiredSize.Width) / 2,
        HorizontalAlignment.Right => childArrangeSize.Width - childDesiredSize.Width,
        _ => 0 // Left or Stretch
    };

    childTop += child.VerticalAlignment switch
    {
        VerticalAlignment.Center => (childArrangeSize.Height - childDesiredSize.Height) / 2,
        VerticalAlignment.Bottom => childArrangeSize.Height - childDesiredSize.Height,
        _ => 0 // Top or Stretch
    };

    // Arrange the Child with alignment taken into account
    Point childPos = new Point(childLeft, childTop);
    child.Arrange(new Rect(childPos, childDesiredSize));

    // ... (arranging sides - code remains the same)

    return arrangementSize;
}

在此修改版本中,我们通过考虑子级的水平和垂直对齐来确定

childLeft
childTop
。子项的
HorizontalAlignment
VerticalAlignment
可以是
Left
Center
Right
Stretch
(与垂直对齐相同)。如果是
Center
,我们将孩子放置在可用空间的中间,减去边框两侧占用的空间。对于
Right
Bottom
,我们将其放置在可用空间的末尾。
Left
Top
将从边界末端开始,这实际上是距边界
0
的距离。

请务必记住,

HorizontalAlignment
VerticalAlignment
的默认行为是
Stretch
。在这种情况下,控件将拉伸以填充可用空间(减去边框占用的空间),如果您实际上在
BorderWrapper
上没有任何空间限制,这可能会使您的边框看起来无效。对于非拉伸对齐,这应该考虑边框占用的空间和所选对齐来定位子项。

确保使用不同的对齐方式和容器大小进行测试,以确保您的控件在各种情况下都能按预期运行。

© www.soinside.com 2019 - 2024. All rights reserved.