Программное создание раскадровки в WPF ControlTemplate

#c# #wpf #xaml #animation

#c# #wpf #xaml #Анимация

Вопрос:

У меня есть приложение WPF, которое загружается Pages в шаблонном NavigationWindow виде . Я хотел бы реализовать переход слайдов при загрузке новой страницы, и поскольку размер окна можно изменять, целевые значения для преобразования должны определяться программно, насколько мне известно.

Я попробовал следующее в NavigationWindow коде, но это не имеет никакого эффекта при срабатывании. PageContentContainerTransform Он также находится в правильном месте, как определено в отладчике.

 public void DoTransition()
{
    double targetX = this.ActualWidth;

    this.TransitionStoryboard.Stop();
    this.TransitionStoryboard.Children.Clear();
    IEasingFunction easing = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
    DoubleAnimation translateXAnim = new DoubleAnimation() {
        To = targetX,
        Duration = TimeSpan.FromMilliseconds(250),
        EasingFunction = easing,
    };

    DependencyObject d = this.Template.FindName("pageContentContainerTransform", this) as DependencyObject;
    Storyboard.SetTarget(translateXAnim, d);

    Storyboard.SetTargetProperty(translateXAnim, new PropertyPath(TranslateTransform.XProperty));
    this.TransitionStoryboard.Children.Add(translateXAnim);
    this.TransitionStoryboard.Begin();
}
 

Это файл Template ControlTemplate , содержащий следующий бит XAML,

 ...
<ContentPresenter 
    Grid.Row="1"
    x:Name="pageContentContainer"
    MaxHeight="{StaticResource ContentWindowMaxHeight}"
    MaxWidth="{StaticResource ContentWindowMaxWidth}"
    RenderTransformOrigin="0.5,0.5">
    <ContentPresenter.RenderTransform>
        <TranslateTransform x:Name="pageContentContainerTransform" X="0" Y="0" />
    </ContentPresenter.RenderTransform>
</ContentPresenter>
...
 

Почему нет никакого эффекта?

Обновить

Анимация работает, если вы анимируете элемент напрямую, не заключая его в Storyboard объект. Например.

 public void DoTransition()
{
    double targetX = this.ActualWidth;

    this.TransitionStoryboard.Stop();
    this.TransitionStoryboard.Children.Clear();
    IEasingFunction easing = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
    DoubleAnimation translateXAnim = new DoubleAnimation() {
        To = targetX,
        Duration = TimeSpan.FromMilliseconds(250),
        EasingFunction = easing,
    };

    TranslateTransform t = this.Template.FindName("pageContentContainerTransform", this) as TranslateTransform;
    t.BeginAnimation(TranslateTransform.XProperty, translateXAnim);

}
 

Однако, по-видимому, вы упускаете некоторые полезные элементы управления для анимации, которые предоставляет объект раскадровки, например, управление анимацией (остановка, запуск и т.д.). По-видимому, существуют возможные аргументы для .Begin() объекта раскадровки, которые уместны для использования в шаблоне, однако вызов with .Begin(this, this.Template) также ничего не делает.

Комментарии:

1. возможно, вы можете создать свойство зависимости, привязать к нему свое преобразование и анимировать свойство для упрощения манипуляций. доступ к объектам внутри элемента управления или шаблона данных — сложная задача. вы также можете попытаться найти любую ошибку данных в окне вывода во время запуска приложения.

2. По какой-то причине я думаю, что это было бы проще, если бы вы использовали визуальный диспетчер состояний, пример, хотя и не совсем то, что вы ищете silverlightshow.net/items /…

3. Преобразования слайдов — непростая задача для разработки. Вам гораздо лучше использовать уже существующую библиотеку, такую как Transitionals .

Ответ №1:

В конце концов, сочетание факторов заставило его работать. Во-первых, используйте Storyboard.SetTargetName вместо Storyboard.SetTarget . Во-вторых, передайте Begin() методу контекст шаблона. Например.

 public void DoTransition()
{
    double targetX = this.ActualWidth;

    this.TransitionStoryboard.Stop();
    this.TransitionStoryboard.Children.Clear();
    IEasingFunction easing = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
    DoubleAnimation translateXAnim = new DoubleAnimation() {
        To = targetX,
        Duration = TimeSpan.FromMilliseconds(250),
        EasingFunction = easing,
    };

    // 1. Refer to the element by Name
    Storyboard.SetTargetName(translateXAnim, "pageContentContainerTransform");
    Storyboard.SetTargetProperty(translateXAnim, new PropertyPath(TranslateTransform.XProperty));
    this.TransitionStoryboard.Children.Add(translateXAnim);
    // 2. Pass in the template context here
    this.TransitionStoryboard.Begin(this, this.Template);    
}
 

Я не понимаю, почему SetTargetProperty это не работает, если учесть, что FindName правильно идентифицирован элемент в шаблоне, но в любом случае вышеуказанные методы работают.