gpt4 book ai didi

wpf - 如何使水平 StackPanel 中排列的元素共享其文本内容的公共(public)基线?

转载 作者:行者123 更新时间:2023-12-03 01:30:20 30 4
gpt4 key购买 nike

这是我遇到的问题的一个简单示例:

<StackPanel Orientation="Horizontal">
<Label>Foo</Label>
<TextBox>Bar</TextBox>
<ComboBox>
<TextBlock>Baz</TextBlock>
<TextBlock>Bat</TextBlock>
</ComboBox>
<TextBlock>Plugh</TextBlock>
<TextBlock VerticalAlignment="Bottom">XYZZY</TextBlock>
</StackPanel>

除了 TextBoxComboBox 之外,这些元素中的每一个都以不同的方式垂直定位它们包含的文本,而且看起来很丑陋。

我可以通过为每个元素指定 Margin 来将这些元素中的文本对齐。这是可行的,只不过边距以像素为单位,并且与显示器的分辨率、字体大小或任何其他可变的因素无关。

我什至不确定如何在运行时计算控件的正确底部边距。

最好的方法是什么?

最佳答案

问题

据我了解,问题是您想要在 StackPanel 中水平布局控件并与顶部对齐,但每个控件中的文本都对齐。此外,您不想为每个控件设置一些内容:StyleMargin

基本方法

问题的根源在于不同的控件在控件边界和其中的文本之间有不同数量的“开销”。当这些控件在顶部对齐时,其中的文本会出现在不同的位置。

所以我们想要做的是应用为每个控件定制的垂直偏移。这应该适用于所有字体大小和所有 DPI:WPF 采用与设备无关的长度度量。

自动化流程

现在我们可以应用 Margin 来获取偏移量,但这意味着我们需要在 StackPanel 中的每个控件上维护它。

我们如何实现自动化?不幸的是,很难找到万无一失的解决方案。可以覆盖控件的模板,这将改变控件中的布局开销量。但是,只要我们可以将控件类型(文本框、标签等)与给定的偏移量关联起来,就可以编写一个可以节省大量手动对齐工作的控件。

解决方案

您可以采取几种不同的方法,但我认为这是一个布局问题,需要一些自定义的测量和排列逻辑:

public class AlignStackPanel : StackPanel
{
public bool AlignTop { get; set; }

protected override Size MeasureOverride(Size constraint)
{
Size stackDesiredSize = new Size();

UIElementCollection children = InternalChildren;
Size layoutSlotSize = constraint;
bool fHorizontal = (Orientation == Orientation.Horizontal);

if (fHorizontal)
{
layoutSlotSize.Width = Double.PositiveInfinity;
}
else
{
layoutSlotSize.Height = Double.PositiveInfinity;
}

for (int i = 0, count = children.Count; i < count; ++i)
{
// Get next child.
UIElement child = children[i];

if (child == null) { continue; }

// Accumulate child size.
if (fHorizontal)
{
// Find the offset needed to line up the text and give the child a little less room.
double offset = GetStackElementOffset(child);
child.Measure(new Size(Double.PositiveInfinity, constraint.Height - offset));
Size childDesiredSize = child.DesiredSize;

stackDesiredSize.Width += childDesiredSize.Width;
stackDesiredSize.Height = Math.Max(stackDesiredSize.Height, childDesiredSize.Height + GetStackElementOffset(child));
}
else
{
child.Measure(layoutSlotSize);
Size childDesiredSize = child.DesiredSize;

stackDesiredSize.Width = Math.Max(stackDesiredSize.Width, childDesiredSize.Width);
stackDesiredSize.Height += childDesiredSize.Height;
}
}

return stackDesiredSize;
}

protected override Size ArrangeOverride(Size arrangeSize)
{
UIElementCollection children = this.Children;
bool fHorizontal = (Orientation == Orientation.Horizontal);
Rect rcChild = new Rect(arrangeSize);
double previousChildSize = 0.0;

for (int i = 0, count = children.Count; i < count; ++i)
{
UIElement child = children[i];

if (child == null) { continue; }

if (fHorizontal)
{
double offset = GetStackElementOffset(child);

if (this.AlignTop)
{
rcChild.Y = offset;
}

rcChild.X += previousChildSize;
previousChildSize = child.DesiredSize.Width;
rcChild.Width = previousChildSize;
rcChild.Height = Math.Max(arrangeSize.Height - offset, child.DesiredSize.Height);
}
else
{
rcChild.Y += previousChildSize;
previousChildSize = child.DesiredSize.Height;
rcChild.Height = previousChildSize;
rcChild.Width = Math.Max(arrangeSize.Width, child.DesiredSize.Width);
}

child.Arrange(rcChild);
}

return arrangeSize;
}

private static double GetStackElementOffset(UIElement stackElement)
{
if (stackElement is TextBlock)
{
return 5;
}

if (stackElement is Label)
{
return 0;
}

if (stackElement is TextBox)
{
return 2;
}

if (stackElement is ComboBox)
{
return 2;
}

return 0;
}
}

我从 StackPanel 的 Measure 和 Arrange 方法开始,然后删除对滚动和 ETW 事件的引用,并根据存在的元素类型添加所需的间距缓冲区。该逻辑仅影响水平堆叠面板。

AlignTop 属性控制间距是否使文本与顶部或底部对齐。

如果控件使用自定义模板,则对齐文本所需的数字可能会发生变化,但您不需要在每个元素上放置不同的 MarginStyle在集合中。另一个优点是您现在可以在子控件上指定 Margin,而不会干扰对齐。

结果:

<local:AlignStackPanel Orientation="Horizontal" AlignTop="True" >
<Label>Foo</Label>
<TextBox>Bar</TextBox>
<ComboBox SelectedIndex="0">
<TextBlock>Baz</TextBlock>
<TextBlock>Bat</TextBlock>
</ComboBox>
<TextBlock>Plugh</TextBlock>
</local:AlignStackPanel>

align top example

AlignTop="False":

align bottom example

关于wpf - 如何使水平 StackPanel 中排列的元素共享其文本内容的公共(public)基线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1983134/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com