2013-07-29 3 views
5

Я пытаюсь создать раскадровку в XAML, которая анимирует свойство одного из дочерних элементов элемента, который вызывает событие. Но я не могу заставить его работать без использования имен, чего я действительно не могу сделать в этой конкретной ситуации.WPF Анимация свойства ребенка без использования имени

Я в основном пытаются что-то вроде этого (очень упрощенный конечно):

<Canvas> 
     <Canvas.Triggers> 
     <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 
      <EventTrigger.Actions> 
       <BeginStoryboard> 
        <Storyboard> 
        <DoubleAnimation Storyboard.TargetProperty="Children[0].(Canvas.Left)" From="0" To="400" /> 
        </Storyboard> 
       </BeginStoryboard> 
      </EventTrigger.Actions> 
     </EventTrigger> 
     </Canvas.Triggers> 

     <Button Canvas.Left="20" Canvas.Top="20">A</Button> 
     <Button Canvas.Left="40" Canvas.Top="20">B</Button> 
    </Canvas> 

Любые идеи о том, как это может быть достигнуто?

ответ

5

При условии, что UIElement вы индексирование в анимации существует (т.е. уже присутствует на Canvas), то вы можете сделать следующее:

<Canvas x:Name="MyCanvas"> 
    <Button x:Name="btn" Canvas.Left="20" Canvas.Top="20">A</Button> 
    <Button Canvas.Left="40" Canvas.Top="20">B</Button> 
    <Canvas.Triggers> 
     <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 
      <EventTrigger.Actions> 
       <BeginStoryboard> 
        <Storyboard> 
         <DoubleAnimation Storyboard.Target="{Binding ElementName=MyCanvas, Path=Children[0]}" 
             Storyboard.TargetProperty="(Canvas.Left)" From="0" To="400" /> 
        </Storyboard> 
       </BeginStoryboard> 
      </EventTrigger.Actions> 
     </EventTrigger> 
    </Canvas.Triggers> 
</Canvas> 

Обратите внимание, как я переместил добавление кнопок над Trigger , Если кнопки находятся ниже Trigger, как и в вашем вопросе, попытка доступа к Children[0] вызовет ArgumentOutOfRangeException, потому что на данный момент детей нет.

+1

Да! Вы выиграли, +1 =). –

1

Чтобы использовать Storyboard.TargetProperty в анимации, он всегда должен быть свойством зависимости. Children собственность получает UIElementCollection дочерних элементов этого Panel (Canvas). Поэтому следующая конструкция Children [n] возвращает UIElement, что должно привести к определенному типу, чтобы получить доступ к свойству зависимости.

Это может быть сделано в коде следующим образом:

Button MyButton = (Button)MyCanvas.Children[0]; 

MessageBox.Show(MyButton.Width.ToString()); 

Все эти действия отсутствующими в анимации по умолчанию, это ваша конструкция не будет работать.

Я предлагаю создать анимацию в коде, где это преобразование возможно.

Чтобы продемонстрировать это, я создал Canvas, в случае Loaded, зарегистрировав анимацию. Номер элемента устанавливается через присоединенное свойство зависимостей (конечно, пример может быть реализован различными способами). Ниже приведен мой пример:

XAML

<Grid> 
    <local:MyCanvas x:Name="MyCanvas" local:ClassForAnimation.Children="1"> 
     <Button Canvas.Left="20" Canvas.Top="20">A</Button> 
     <Button Canvas.Left="40" Canvas.Top="20">B</Button> 
    </local:MyCanvas> 
</Grid> 

Code behind

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    }  
} 

public class MyCanvas : Canvas 
{ 
    public MyCanvas() 
    { 
     this.Loaded += new RoutedEventHandler(MyCanvas_Loaded); 
    } 

    private void MyCanvas_Loaded(object sender, RoutedEventArgs e) 
    { 
     MyCanvas myCanvas = sender as MyCanvas; 

     // Get No. of children 
     int children = ClassForAnimation.GetChildren(myCanvas); 

     // Get current Button for animation 
     Button MyButton = (Button)myCanvas.Children[children]; 

     if (myCanvas != null) 
     { 
      DoubleAnimation doubleAnimation = new DoubleAnimation(); 

      doubleAnimation.From = 0; 
      doubleAnimation.To = 400; 

      MyButton.BeginAnimation(Button.WidthProperty, doubleAnimation); 
     } 
    } 
} 

public class ClassForAnimation : DependencyObject 
{ 
    public static readonly DependencyProperty ChildrenProperty; 

    public static void SetChildren(DependencyObject DepObject, int value) 
    { 
     DepObject.SetValue(ChildrenProperty, value); 
    } 

    public static int GetChildren(DependencyObject DepObject) 
    { 
     return (int)DepObject.GetValue(ChildrenProperty); 
    } 

    static ClassForAnimation() 
    { 
     PropertyMetadata MyPropertyMetadata = new PropertyMetadata(0); 

     ChildrenProperty = DependencyProperty.RegisterAttached("Children", 
                  typeof(int), 
                  typeof(ClassForAnimation), 
                  MyPropertyMetadata); 
    }  
} 

Note: Доступ к элементам Canvas должно быть сделано только в том случае, Loaded, или когда она закончилась. В противном случае элементы недоступны, так как они не загружены.

Смежные вопросы