绑定到 ActualWidth 不起作用 [英] Binding to ActualWidth does not work

查看:21
本文介绍了绑定到 ActualWidth 不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Silverlight 3.0 应用程序中,我试图在画布中创建一个矩形,并让它拉伸画布的整个宽度.我试图通过绑定到父容器的 ActualWidth 属性来做到这一点(参见下面的示例),但是虽然我没有看到任何绑定错误,但该值没有被绑定.该矩形不可见,因为其宽度为零.此外尝试绑定到包含我的矩形的画布的 ActualWidth ,但这没有任何区别.

In a Silverlight 3.0 application I'm attempting to create a rectangle in a canvas and have it stretch the whole width of the canvas. I have attempted to do this by binding to the ActualWidth property of a parent container (seem sample below), however while I don't see any binding errors the value is not being bound. The rectangle is not visible as its width is zero. In addition tried binding to the ActualWidth of the canvas that contains my rectangle but this made no difference.

发现此错误记录在 Microsoft Connect 上,但是没有列出解决方法.

I did find this bug logged on Microsoft Connect but there were no workarounds listed.

有没有人能够解决这个问题,或者他们可以指出解决方案吗?

Has anyone been able to solve this issue or can they point to solution?

原始代码示例与我要实现的目标不准确,为了更清晰而进行了更新.

The original code sample was not accurate of what I'm trying to achieve, updated for more clarity.

<UserControl>
    <Border BorderBrush="White"
            BorderThickness="1"
            CornerRadius="4"
            HorizontalAlignment="Center">
        <Grid x:Name="GridContainer">
            <Rectangle Fill="Aqua"
                       Width="150"
                       Height="400" />
            <Canvas>
                <Rectangle Width="{Binding Path=ActualWidth, ElementName=GridContainer}"
                           Height="30"
                           Fill="Red" />
            </Canvas>

            <StackPanel>
                <!-- other elements here -->
            </StackPanel>
        </Grid>
    </Border>
</UserControl>

推荐答案

您想做什么,需要将数据绑定到 ActualWidth 属性?这是 Silverlight 的一个已知问题,没有简单的解决方法.

What are you trying to do that requires you to databind to the ActualWidth property? This is a known issue with Silverlight, and there is no simple workaround.

可以做的一件事是以这样一种方式设置可视化树,您不需要实际设置矩形的宽度,只需让它拉伸到适当的大小即可.因此,在上面的示例中,如果您移除 Canvas(或将 Canvas 更改为其他面板)并将 RectangleHorizo​​ntalAlignment 设置为 Stretch,它将占用所有可用的宽度(实际上是网格的宽度).

One thing that could be done is to set up the visual tree in such a way that you do not need to actually set the Width of the Rectangle, and just allow it to stretch to the appropriate size. So in the example above, if you remove the Canvas (or change the Canvas to some other Panel) and leave the Rectangle's HorizontalAlignment set to Stretch, it will take up all of the available width (effectively the Width of the Grid).

但是,这在您的特定情况下可能是不可能的,并且可能真的有必要设置数据绑定.已经确定这不是直接可能的,但是在代理对象的帮助下,我们可以设置所需的绑定.考虑这个代码:

However, this may not be possible in your particular case, and it may really be necessary to set up the databinding. It has already been established that this is not possible directly, but with the help of a proxy object, we can set up the required binding. Consider this code:

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

我们可以在 xaml 中使用它,如下所示:

We can use this in xaml as follows:

<Grid x:Name="LayoutRoot">
    <Grid.Resources>
        <c:ActualSizePropertyProxy Element="{Binding ElementName=LayoutRoot}" x:Name="proxy" />
    </Grid.Resources>
    <TextBlock x:Name="tb1" Text="{Binding ActualWidthValue, ElementName=proxy}"  />
</Grid>

所以我们将 TextBlock.Text 绑定到代理对象上的 ActualWidthValue.代理对象依次提供 Element 的 ActualWidth,由另一个 Binding 提供.

So we are Binding TextBlock.Text to the ActualWidthValue on the proxy object. The proxy object in turn provides the ActualWidth of the Element, which is provided by another Binding.

这不是一个简单的问题解决方案,但它是我能想到的如何将数据绑定到 ActualWidth 的最好方法.

This is not a simple solution to the problem, but it is the best that I can think of for how to databind to ActualWidth.

如果您多解释一下您的场景,或许可以想出一个更简单的解决方案.可能根本不需要数据绑定;是否可以仅通过 SizeChanged 事件处理程序中的代码设置属性?

If you explained your scenario a bit more, it may be possible to come up with a simpler solution. DataBinding may not be required at all; would it be possible to just set the property from code in a SizeChanged event handler?

这篇关于绑定到 ActualWidth 不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆