如何绑定到控件的文字实际宽度(包括其边距)?
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 宽度而是没有边距的宽度。
- 我是不是把什么东西弄糊涂了?如果是,怎么办?
- 如何获取并绑定到 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.Width
或 DesiredSize.Height
。这将考虑保证金。但它是一个 UIElement。
根据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 宽度而是没有边距的宽度。
- 我是不是把什么东西弄糊涂了?如果是,怎么办?
- 如何获取并绑定到 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.Width
或 DesiredSize.Height
。这将考虑保证金。但它是一个 UIElement。