绑定到儿童在运行时不起作用

时间:2018-02-05 11:19:09

标签: c# wpf layout binding

我将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,因此“文本”重叠,绑定 - 文本位于设计器中的 (您可以自己尝试)。< / p>

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

  

System.Windows.Data错误:17:无法从'Children'获取'Item []'值(类型'UIElement')(类型'UIElementCollection')。 BindingExpression:路径=儿童[0] .ActualHeight; DataItem ='Canvas'(Name =''); target元素是'Canvas'(Name =''); target属性为'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}}"。它适用于设计师,但不适用于运行时!

2 个答案:

答案 0 :(得分:1)

作为@MartinZikmund评论

  

问题是在孩子实际存在之前评估运行时绑定

第二个例子可以改写为

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

答案 1 :(得分:1)

你可以把它放在一个行为上:

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 } });
}