如何绑定到控件的文字实际宽度(包括其边距)?

How to bind to a control's literal actual width (including its margins)?

根据some folks实际宽度是使用ActualWidth属性获得的,如下例所示。这是有道理的,但我似乎经历了矛盾的行为。

<Canvas Width="{Binding ActualWidth,ElementName=Expy}">
  <Expander x:Name="Expy"
                    HorizontalAlignment="Left"
                    Margin="0,0,0,0"
                    VerticalAlignment="Top" ...>
  ...
  </Expander>
</Canvas>

在上面的设置中,行为与预期一致,虽然紧密挤压在一起,但面板中包含 canvas 的下一个元素与其前一个元素不重叠。

但是,如果我将边距更改得更宽一点,我可以清楚地看到 canvas 侵入了下一个元素,估计与我在边距属性中请求的小精灵数量相同。所以看起来 ActualWidth 不是 actual 宽度而是没有边距的宽度。

  1. 我是不是把什么东西弄糊涂了?如果是,怎么办?
  2. 如何获取并绑定到 actaully 实际渲染宽度?

链接的答案是:

ActualWidth accounts for padding and margins ...

这是不正确的。 ActualWidth 包括 填充,而不包括边距(与 ActualHeight 相同)。

其他人对该答案留下的评论提供了适当的更正。


这段 XAML 代码说明了这个问题:

<Window x:Class="..."
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <TextBlock x:Name="First" Text="Some text" Padding="10" Margin="0,0"
            HorizontalAlignment="Left" Background="Yellow" />
        <TextBlock Text="{Binding ActualWidth, ElementName=First}" />

        <TextBlock x:Name="Second" Text="Some text" Padding="10" Margin="10,0"
            HorizontalAlignment="Left" Background="LimeGreen" />
        <TextBlock Text="{Binding ActualWidth, ElementName=Second}" />
    </StackPanel>
</Window>

如果你 运行 这你会看到两个 "Some text" 文本块具有相同的 ActualWidth 值,尽管第二个文本块应用了水平边距。


你问你如何考虑到这一点。没有办法通过绑定来做到这一点,因为 ActualWidth 属性 不包括已经说明的边距。您可以做的是将边距应用于父元素(canvas)而不是将其应用于扩展器。

换句话说,不是这样做:

<Canvas Width="{Binding ActualWidth,ElementName=Expy}">
    <Expander x:Name="Expy" ... Margin="10" ... >
        ...
    </Expander>
</Canvas>

这样做:

<Canvas Width="{Binding ActualWidth,ElementName=Expy}" Margin="10">
    <Expander x:Name="Expy" ... >
        ...
    </Expander>
</Canvas>

是的,康拉德。你糊涂了。

只要我们指的是 Actual(Height/Width),它就是渲染的。你是对的。但是,Actual(Height/Width) 值在包括测量和排列阶段的 WPF 布局过程之后得到初始化,这是您首先需要了解的内容,以了解问题的真正原因。

首先,使用实际值绑定任何内容永远不会给您想要的结果,因为这样做会违反 WPF 布局链。根据 WPF 布局阶段,在 Measure 阶段 WPF 获取布局中每个控件的指定大小(例如,在高度和宽度中指定的值),然后在 Arrange 阶段它实际上以最佳方式将控件分配给布局。指定的大小在排列阶段后可能会有所不同。

此外,需要注意的是,实际参数包括渲染大小加上填充值(但不包括边距)。在您的示例中,我猜 Expander 控件旁边的另一个面板是您报告的问题背后的原因。我只有看到整个布局才能确认。

但作为预防措施,您始终可以停止使用实际参数进行绑定。您绝对可以使用 Width 和 Height 值进行绑定。

您不能在 ActualWidth 中包含边距。一个解决方案是使用 DesiredSize.WidthDesiredSize.Height。这将考虑保证金。但它是一个 UIElement。