首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >绑定到ActualWidth不起作用

绑定到ActualWidth不起作用
EN

Stack Overflow用户
提问于 2009-10-22 00:55:50
回答 8查看 21.7K关注 0票数 24

在Silverlight3.0应用程序中,我尝试在画布中创建一个矩形,并让它拉伸整个画布的宽度。我曾尝试通过绑定到父容器的ActualWidth属性(见下面的示例)来实现这一点,然而,虽然我没有看到任何绑定错误,但值并未被绑定。矩形不可见,因为其宽度为零。此外,我还尝试绑定到包含矩形的画布的ActualWidth,但这没有什么不同。

我使用了find this bug logged on Microsoft Connect,但没有列出解决方法。

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

编辑:原始代码样本并不能准确反映我想要实现的目标,为了更清晰起见,我进行了更新。

代码语言:javascript
复制
<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>
EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2009-10-22 10:03:31

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

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

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

代码语言:javascript
复制
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中使用它,如下所示:

代码语言:javascript
复制
<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。代理对象反过来提供元素的ActualWidth,该元素由另一个绑定提供。

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

如果您更多地解释了您的场景,可能会提出一个更简单的解决方案。可能根本不需要DataBinding;是否可以只通过SizeChanged事件处理程序中的代码设置该属性?

票数 32
EN

Stack Overflow用户

发布于 2011-07-29 00:44:23

使用附加属性的机制,可以定义表示ActualHeightActualWidth并由SizeChanged事件更新的属性。它的用法如下所示。

代码语言:javascript
复制
<Grid local:SizeChange.IsEnabled="True" x:Name="grid1">...</Grid>

<TextBlock Text="{Binding ElementName=grid1,
                         Path=(local:SizeChange.ActualHeight)}"/>

有关技术详细信息,请访问以下网址:

http://darutk-oboegaki.blogspot.com/2011/07/binding-actualheight-and-actualwidth.html

与其他解决方案相比,此解决方案的优势在于,解决方案中定义的附加属性(SizeChange.ActualHeight和SizeChange.ActualWidth)可用于任何FrameworkElement,而无需创建任何子类。此解决方案可重复使用,侵入性更小。

如果链接变得陈旧,下面是链接上显示的SizeChange类:

代码语言:javascript
复制
// Declare SizeChange class as a sub class of DependencyObject

// because we need to register attached properties.
public class SizeChange : DependencyObject
 {
     #region Attached property "IsEnabled"

    // The name of IsEnabled property.
    public const string IsEnabledPropertyName = "IsEnabled";

    // Register an attached property named "IsEnabled".
    // Note that OnIsEnabledChanged method is called when
    // the value of IsEnabled property is changed.
    public static readonly DependencyProperty IsEnabledProperty
         = DependencyProperty.RegisterAttached(
             IsEnabledPropertyName,
             typeof(bool),
             typeof(SizeChange),
             new PropertyMetadata(false, OnIsEnabledChanged));

    // Getter of IsEnabled property. The name of this method
    // should not be changed because the dependency system
    // uses it.
    public static bool GetIsEnabled(DependencyObject obj)
     {
         return (bool)obj.GetValue(IsEnabledProperty);
     }

    // Setter of IsEnabled property. The name of this method
    // should not be changed because the dependency system
    // uses it.
    public static void SetIsEnabled(DependencyObject obj, bool value)
     {
         obj.SetValue(IsEnabledProperty, value);
     }

     #endregion

     #region Attached property "ActualHeight"

    // The name of ActualHeight property.
    public const string ActualHeightPropertyName = "ActualHeight";

    // Register an attached property named "ActualHeight".
    // The value of this property is updated When SizeChanged
    // event is raised.
    public static readonly DependencyProperty ActualHeightProperty
         = DependencyProperty.RegisterAttached(
             ActualHeightPropertyName,
             typeof(double),
             typeof(SizeChange),
             null);

    // Getter of ActualHeight property. The name of this method
    // should not be changed because the dependency system
    // uses it.
    public static double GetActualHeight(DependencyObject obj)
     {
         return (double)obj.GetValue(ActualHeightProperty);
     }

    // Setter of ActualHeight property. The name of this method
    // should not be changed because the dependency system
    // uses it.
    public static void SetActualHeight(DependencyObject obj, double value)
     {
         obj.SetValue(ActualHeightProperty, value);
     }

     #endregion

     #region Attached property "ActualWidth"

    // The name of ActualWidth property.
    public const string ActualWidthPropertyName = "ActualWidth";

    // Register an attached property named "ActualWidth".
    // The value of this property is updated When SizeChanged
    // event is raised.
    public static readonly DependencyProperty ActualWidthProperty
         = DependencyProperty.RegisterAttached(
             ActualWidthPropertyName,
             typeof(double),
             typeof(SizeChange),
             null);

    // Getter of ActualWidth property. The name of this method
    // should not be changed because the dependency system
    // uses it.
    public static double GetActualWidth(DependencyObject obj)
     {
         return (double)obj.GetValue(ActualWidthProperty);
     }

    // Setter of ActualWidth property. The name of this method
    // should not be changed because the dependency system
    // uses it.
    public static void SetActualWidth(DependencyObject obj, double value)
     {
         obj.SetValue(ActualWidthProperty, value);
     }

     #endregion

    // This method is called when the value of IsEnabled property
    // is changed. If the new value is true, an event handler is
    // added to SizeChanged event of the target element.
    private static void OnIsEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
     {
        // The given object must be a FrameworkElement instance,
        // because we add an event handler to SizeChanged event
        // of it.
        var element = obj as FrameworkElement;

         if (element == null)
         {
            // The given object is not an instance of FrameworkElement,
            // meaning SizeChanged event is not available. So, nothing
            // can be done for the object.
            return;
         }

        // If IsEnabled=True
        if (args.NewValue != null && (bool)args.NewValue == true)
         {
             // Attach to the element.
             Attach(element);
         }
         else
         {
             // Detach from the element.
             Detach(element);
         }
     }

     private static void Attach(FrameworkElement element)
     {
        // Add an event handler to SizeChanged event of the element

        // to take action when actual size of the element changes.
        element.SizeChanged += HandleSizeChanged;
     }

     private static void Detach(FrameworkElement element)
     {
        // Remove the event handler from the element.
        element.SizeChanged -= HandleSizeChanged;
     }

    // An event handler invoked when SizeChanged event is raised.
    private static void HandleSizeChanged(object sender, SizeChangedEventArgs args)
     {
         var element = sender as FrameworkElement;

         if (element == null)
         {
             return;
         }

        // Get the new actual height and width.
        var width  = args.NewSize.Width;
         var height = args.NewSize.Height;

        // Update values of SizeChange.ActualHeight and

        // SizeChange.ActualWidth.
        SetActualWidth(element, width);
         SetActualHeight(element, height);
     }
 }
票数 21
EN

Stack Overflow用户

发布于 2010-11-15 07:34:53

我的解决方案是声明名为RealWidth的我自己的DependencyProperty,并在SizeChanged事件上更新它的值。然后,您可以绑定到RealWidth,它将更新,这与ActualWidth属性不同。

代码语言:javascript
复制
public MyControl()
{
    InitializeComponent();
    SizeChanged += HandleSizeChanged;
}

public static DependencyProperty RealWidthProperty =
     DependencyProperty.Register("RealWidth", typeof (double),
     typeof (MyControl),
     new PropertyMetadata(500D));

public double RealWidth
{
    get { return (double) GetValue(RealWidthProperty); }
    set { SetValue(RealWidthProperty, value); }
}

private void HandleSizeChanged(object sender, SizeChangedEventArgs e)
{
    RealWidth = e.NewSize.Width;
}
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1602148

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档