开发者

Why is my WPF binding not working in state change?

I have some items in a WrapPanel. I want to be able to click on an item and have it expand to the full width of the wrap panel. I tried doing this by creating two states, Expanded and Colapsed, in the control that is used for each item. For the Expanded state, I bound the Width of the control to be equal to the ActualWidth of the WrapPanel.

When I didn't get the result I expected, I tried setting Expanded value to a specific number (instead of the the binding). That is working. The items toggle between the two Colapsed and Exapanded widths. I still want to have the Expanded state be equal to the width of the WrapPanel though, not an arbitrary fixed width. I know my binding works because if I just bind the Width property directly (not via visual states), the items in the WrapPanel match its width.

Expanded state with Binding - Doesn't work:

<VisualState x:Name="Expanded">
<Storyboard>
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="JobMaster">
        <EasingDoubleKeyFrame KeyTime="0">
            <EasingDoubleKeyFrame.Value>
                 <Binding 
                   Path="ActualWidth"
                   RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type WrapPanel}}" />
            </EasingDoubleKeyFrame.Value>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Expanded State with hard coded value - Works

<VisualState x:Name="Expanded">
<Storyboard>
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="JobMaste开发者_如何学编程r">
        <EasingDoubleKeyFrame KeyTime="0" Value="800" />
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

Bind the control Width property directly works

<UserControl.Width>
       <Binding 
       Path="ActualWidth"
       RelativeSource="{RelativeSource AncestorType={x:Type WrapPanel}}" />
</UserControl.Width>

So why doesn't the Binding in the state work or is there another way to do this?


I was never able to get this working using visual states. Instead I wrote a behavoir.

public class TileExpandColapseBehavoir : Behavior<Control>
{
    private ITile _data;

    #region Properties

    public static readonly DependencyProperty TileControlProperty = DependencyProperty.Register("TileControl", typeof(object), typeof(TileExpandColapseBehavoir), new PropertyMetadata(null));
    public static readonly DependencyProperty DefaultWidthProperty = DependencyProperty.Register("DefaultWidth", typeof(Double), typeof(TileExpandColapseBehavoir), new PropertyMetadata(null));

    public object TileControl
    {
        get { return (object)this.GetValue(TileControlProperty); }
        set { this.SetValue(TileControlProperty, value); }
    }

    public double DefaultWidth
    {
        get { return (double)this.GetValue(DefaultWidthProperty); }
        set { this.SetValue(DefaultWidthProperty, value); }
    }

    #endregion

    public TileExpandColapseBehavoir()
    {
    }

    protected override void OnAttached()
    {
        this.AssociatedObject.PreviewMouseDown +=new MouseButtonEventHandler(AssociatedObject_MouseUp);  
    }

    private void AssociatedObject_MouseUp(object sender, MouseButtonEventArgs e)
    {
        UIElement child = (UIElement)sender;
        WrapPanel parentWrap = FindAncestorUtil.TryFindAcestor<WrapPanel>(child);
        if (parentWrap != null && TileControl is UserControl)
        {
            GetData();
            if (_data.IsExpanded == false)
            {
                Binding newBinding = new Binding();
                newBinding.Source = parentWrap;
                newBinding.Path = new PropertyPath("ActualWidth");

                UserControl thisTile = (UserControl)TileControl;
                BindingOperations.SetBinding(thisTile, UserControl.WidthProperty, newBinding);
                _data.IsExpanded = true;
            }
            else
            {
                UserControl thisTile = (UserControl)TileControl;

                BindingOperations.ClearBinding(thisTile, UserControl.WidthProperty);
                thisTile.Width = DefaultWidth;
                _data.IsExpanded = false;
            }
        }
    }

    private void GetData()
    {
        if (_data == null && AssociatedObject.DataContext is ITile)
        {  
             _data = (ITile)AssociatedObject.DataContext;
        }
    }
}


Your RelativeSource binding is looking for an ancestor of the animation, not the target of the animation. Try giving your WrapPanel a name and use Element binding instead.

<Binding Path="ActualWidth" ElementName="MyWrapPanel"/>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜