【问题标题】:Binding to Children does not work at run-time绑定到子级在运行时不起作用
【发布时间】:2018-07-15 05:49:27
【问题描述】:

我将Canvas 高度绑定到第一个孩子的高度,以便可以正确布局,布局示例:

<StackPanel>
    <Canvas Height="{Binding Children[0].ActualHeight , RelativeSource={RelativeSource Self}}">
        <Rectangle Height="100" Width="100" Fill="Red" />
    </Canvas>
    <TextBlock Text="Text" />
</StackPanel>

不绑定Canvas.Height值为0,这样“Text”重叠,有绑定——文本在indesigner下(你可以自己试试)。

但是在运行时绑定失败并且文本重叠。

System.Windows.Data 错误:17:无法从“Children”(类型“UIElementCollection”)获取“Item[]”值(类型“UIElement”)。 BindingExpression:Path=Children[0].ActualHeight;数据项='画布'(名称='');目标元素是 'Canvas' (Name='');目标属性为“Height”(类型“Double”) ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: 指定的参数超出了有效值的范围。

为什么?我可以在运行时有设计器时的行为吗?

我希望给孩子一个x:Name 并使用ElementName 进行绑定。


这里有更好的 MCVE:

<ListBox>
    <TextBlock Text="1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1" />
    <TextBlock Text="2" />
    <TextBlock Text="3" />
    <Canvas Height="100">
        <TextBlock Canvas.Left="{Binding HorizontalOffset, RelativeSource={RelativeSource AncestorType=ScrollViewer}}"
                   Text="Frozen" />
    </Canvas>
    <TextBlock Text="4" />
    <TextBlock Text="5" />
</ListBox>

它是这样工作的:

"Frozen" 停留在屏幕上忽略水平滚动,但仍被视为一个项目(垂直滚动可以将其移出视图)。这可以通过Canvas 属性来实现:它具有0 高度和宽度,并且不会对布局造成任何影响。注意绑定到HorizontalOffset

Height="100" 替换为Height="{Binding Children[0].ActualHeight, RelativeSource={RelativeSource Self}}"。它适用于设计器,但不适用于运行时!

【问题讨论】:

  • 这一切的目的是什么?通常可以通过使用适当的布局元素来避免绑定宽度和高度。例如。用网格或边框替换画布。
  • @Clemens,创建布局。画布将成为ListViewItem 的一部分(模拟冻结内容,不考虑水平滚动),但内容在数据模板中,我虽然我可以像这样自动调整Canvas,否则@987654338 @ 太小(Canvas.Height0,正如我所说)。
  • 但是当其他面板已经实现自动调整大小时,为什么要“自动调整”画布?
  • Canvas 很特别。任何其他容器都会影响ListView 列/行,Canvas - 不会。它允许创建ListViewItem之上的内容。
  • 我认为问题在于运行时的 Binding 在孩子实际存在之前被评估。为什么不能为此使用ElementName 绑定?这似乎很合适

标签: c# wpf layout binding


【解决方案1】:

作为@MartinZikmund 评论

问题在于,运行时的 Binding 是在子实际存在之前评估的

第二个例子可以改写为

<Canvas>
    <TextBlock Canvas.Left="{Binding HorizontalOffset, RelativeSource={RelativeSource AncestorType=ScrollViewer}}"
               Text="Frozen" />
    <Canvas.Height>
        <Binding Path="Children[0].ActualHeight" RelativeSource="{RelativeSource Self}" />
    </Canvas.Height>
</Canvas>

Height 绑定设置在 内容之后。这使它在运行时工作。

仍然是为什么设计师时间没有问题的问题。我猜是一些 wpf 魔法。

【讨论】:

  • 这是一个有趣的解决方案:-D!
【解决方案2】:

你可以把它变成一种行为:

private void Canvas_Loaded(object sender, RoutedEventArgs e)
{
    (sender as Canvas)?.SetBinding(Canvas.HeightProperty, new Binding("Children[0].ActualHeight") { RelativeSource=new RelativeSource { Mode= RelativeSourceMode.Self } });
}

【讨论】:

  • Loaded 在 xaml 完全处理后触发(内容应该可用),因此这也应该有效,有助于避免完全绑定语法。谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 2012-04-15
  • 2010-12-08
  • 2015-05-23
相关资源
最近更新 更多