如何将控件高度绑定到另一个控件的高度?

7

我想让两个控件具有相同的高度。我能否只使用XAML实现?

如果我这样做,<Canvas Height="{Binding Height, ElementName=AnotherControl}" /> 实际上什么也不会发生,高度变为零。输出面板没有抱怨任何绑定错误,因此AnotherControl.Height确实存在。我尝试将其绑定到ActualHeight,但它也没有作用。

还有其他我可能遗漏的吗?


如果您使用的是WinRT XAML,那么您应该删除WPF标签,这与@Clemens的评论相同。 - Walt Ritscher
3个回答

12

我猜想您的 AnotherControl 没有明确地给出 Height。 不幸的是,在 WinRT 中(与 WPF 不同,但与 Silverlight 相同),ActualWidthActualHeight 是所谓的 "计算属性"。 这意味着当它们改变时,没有引发属性更改事件。 结果,对它们进行绑定不可靠,正如您已经注意到的那样,这样做并不能完全起作用。

旁注:这可能在某些时候有效,但纯粹是因为绑定框架调用 ActualHeight 的获取时间。

因此,现在您不能仅使用 XAML 来完成它。 您必须在代码后台中处理 ActualControl.SizeChanged 事件,并将 Height 显式设置为 AnotherControl.ActualHeight


我想使用XAML的原因是控件在多层项模板中,如果通过代码访问它们可能会很昂贵。 - xster
即使仅在XAML中实现,成本也是相同的。绑定引擎执行的操作与您执行的操作相同... 它会在依赖属性/INPC属性上注册属性更改事件,并将值从绑定源分配到目标。您只需在代码中复制该操作。 - K Mehta

7
如Kshitij Mehta所提到的,在WinRT中绑定ActualHeight和ActualWidth并不可靠。但是有一个很好的解决方法,您不必使用SizeChanged事件:
添加这个类:
public class ActualSizePropertyProxy : FrameworkElement, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public FrameworkElement Element
    {
        get { return (FrameworkElement)GetValue(ElementProperty); }
        set { SetValue(ElementProperty, value); }
    }

    public double ActualHeightValue
    {
        get { return Element == null ? 0 : Element.ActualHeight; }
    }

    public double ActualWidthValue
    {
        get { return Element == null ? 0 : Element.ActualWidth; }
    }

    public static readonly DependencyProperty ElementProperty =
        DependencyProperty.Register("Element", typeof(FrameworkElement), typeof(ActualSizePropertyProxy),
                                    new PropertyMetadata(null, OnElementPropertyChanged));

    private static void OnElementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((ActualSizePropertyProxy)d).OnElementChanged(e);
    }

    private void OnElementChanged(DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement oldElement = (FrameworkElement)e.OldValue;
        FrameworkElement newElement = (FrameworkElement)e.NewValue;

        newElement.SizeChanged += new SizeChangedEventHandler(Element_SizeChanged);
        if (oldElement != null)
        {
            oldElement.SizeChanged -= new SizeChangedEventHandler(Element_SizeChanged);
        }
        NotifyPropChange();
    }

    private void Element_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        NotifyPropChange();
    }

    private void NotifyPropChange()
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("ActualWidthValue"));
            PropertyChanged(this, new PropertyChangedEventArgs("ActualHeightValue"));
        }
    }
}

将其放置在资源中:

<UserControl.Resources>
    <c:ActualSizePropertyProxy Element="{Binding ElementName=YourElement}" x:Name="proxy" />
</UserControl.Resources>

并将其绑定到属性:

<TextBlock x:Name="tb1" Text="{Binding ActualWidthValue, ElementName=proxy}"  />

2
这个问题很古老,但这是我的解决方案。 您可以使用这段代码。
<!--First Button-->
<Button x:Name="button1" Height="50" Width="100"/>

<!--Second Button-->
<Button x:Name="button2" Height="50" Width="{Binding ElementName=button1, Path=Width}"/>

我已在我的Windows/ Windows Phone 8.1设备上测试过它,效果非常好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接