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"/>
精彩评论