【问题标题】:How to bind to a control's literal actual width (including its margins)?如何绑定到控件的文字实际宽度(包括其边距)?
【发布时间】:2015-04-06 08:59:51
【问题描述】:

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

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

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

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

  1. 我是否在这里混淆了某些东西,如果有,是什么?
  2. 如何获取并绑定到实际实际的渲染宽度?

【问题讨论】:

  • 使用合适的布局面板,例如Grid 而不是 Canvas,并移除 Width 绑定。
  • 我同意克莱门斯的观点。我倾向于使用使用 RowDefinitions 和 ColumnDefinitions 的网格布局。大多数时候我不会在任何东西上设置宽度,而只是允许它相对于窗口调整大小。
  • 好吧,在我看来,只有边距不是元素宽度/高度的一部分才有意义。这就是它们与填充物的区别。
  • @Clemens 根据 OP 试图实现的目标,在这种情况下使用 Canvas 没有任何问题(请参阅 this SO question)。
  • @MikeEason 还有其他一些限制我使用画布/扩展器的考虑。当然,如果需要,这可能会改变,所以我欢迎这个建议。但是,对于问题的第二部分,我仍然很好奇 - 如果需要在遵守边距设置的同时绑定到宽度,该怎么办?

标签: c# wpf xaml layout data-binding


【解决方案1】:

链接的答案说:

ActualWidth 用于填充和边距...

这是不正确的。 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>

如果您运行此程序,您将看到两个“某些文本”文本块具有相同的 ActualWidth 值,尽管第二个文本块应用了水平边距。


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

换句话说,不要这样做:

<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>

【讨论】:

  • 哦,建议的解决方法 +1。正如我在对 Clemens 的评论中所描述的,我几乎要玩额外的面板等。您的提示似乎不那么费力了。
【解决方案2】:

是的,康拉德。你很困惑。

当我们指的是实际(高度/宽度)时,它就是渲染的。你是对的。但是,实际(高度/宽度)值在 WPF 布局过程(包括测量和排列阶段)之后被初始化,这是您需要首先了解问题的真正原因。

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

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

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

【讨论】:

  • 酷。我实际上不喜欢使用ActualWidth。我只是遵循了在回答我的另一个问题时提出的提示。也许我应该更加怀疑,但我相信这个建议。谢谢。 (另外,我认为你的意思是我混淆了某事,而不是我混淆了,呵呵。)
  • @KonradViltersten 在某些情况下绑定到ActualWidth(或ActualHeight)没有任何问题。许多人似乎在说,您可以在不绑定这些属性的情况下做您想做的事。然而,没有人展示任何支持这些论点的代码。我可能被证明是错误的,但我怀疑如果不使用外部网格元素使 XAML 复杂化显式设置扩展器控件的宽度,您将无法获得所需的布局。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    • 2023-02-20
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    相关资源
    最近更新 更多