WPF Storyboard работает хорошо, за исключением первого запуска.Зачем? - PullRequest
1 голос
/ 14 июня 2010

Я делаю приложение поверхности. И там у меня есть что-то вроде доски объявлений, на которой наклеены маленькие карточки с новостями. При щелчке они вылетят из доски и станут больше. Моя раскадровка работает хорошо, за исключением первого запуска. Это не плавная анимация, но она сразу масштабируется до конечного размера, и то же самое со свойством direction Кажется, только свойство center ведет себя корректно.

Это пример того, как один из моих раскадровок делает это:

            Storyboard stb = new Storyboard();
            PointAnimation moveCenter = new PointAnimation();
            DoubleAnimationUsingKeyFrames changeWidth = new DoubleAnimationUsingKeyFrames();
            DoubleAnimationUsingKeyFrames changeHeight = new DoubleAnimationUsingKeyFrames();
            DoubleAnimationUsingKeyFrames changeOrientation = new DoubleAnimationUsingKeyFrames();

            moveCenter.From = News1.ActualCenter;
            moveCenter.To = new Point(250, 400);
            moveCenter.Duration = new Duration(TimeSpan.FromSeconds(1.0));
            moveCenter.FillBehavior = FillBehavior.Stop;
            stb.Children.Add(moveCenter);
            Storyboard.SetTarget(moveCenter, News1);
            Storyboard.SetTargetProperty(moveCenter, new PropertyPath(ScatterViewItem.CenterProperty));

            changeWidth.Duration = TimeSpan.FromSeconds(1);
            changeWidth.KeyFrames.Add(new EasingDoubleKeyFrame(266, KeyTime.FromTimeSpan(new System.TimeSpan(0, 0, 1))));
            changeWidth.FillBehavior = FillBehavior.Stop;
            stb.Children.Add(changeWidth);
            Storyboard.SetTarget(changeWidth, News1);
            Storyboard.SetTargetProperty(changeWidth, new PropertyPath(FrameworkElement.WidthProperty));

            changeHeight.Duration = TimeSpan.FromSeconds(1);
            changeHeight.KeyFrames.Add(new EasingDoubleKeyFrame(400, KeyTime.FromTimeSpan(new System.TimeSpan(0, 0, 1))));
            changeHeight.FillBehavior = FillBehavior.Stop;
            stb.Children.Add(changeHeight);
            Storyboard.SetTarget(changeHeight, News1);
            Storyboard.SetTargetProperty(changeHeight, new PropertyPath(FrameworkElement.HeightProperty));

            changeOrientation.Duration = TimeSpan.FromSeconds(1);
            changeOrientation.KeyFrames.Add(new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(new System.TimeSpan(0, 0, 1))));
            changeOrientation.FillBehavior = FillBehavior.Stop;
            stb.Children.Add(changeOrientation);
            Storyboard.SetTarget(changeOrientation, News1);
            Storyboard.SetTargetProperty(changeOrientation, new PropertyPath(ScatterViewItem.OrientationProperty));

            stb.Begin(this);

            News1.Center = new Point(250, 400);
            News1.Orientation = 0;
            News1.Width = 266;
            News1.Height = 400;
            Pin1.Visibility = Visibility.Collapsed;
            news1IsOutside = true;
            Scroll1.IsEnabled = true;

Что с ним не так?

Ответы [ 2 ]

2 голосов
/ 16 июня 2010

Проблема

Суть проблемы в том, что вы вызываете stb.Begin (), а затем немедленно меняете News1.Width и т. Д. К сожалению, stb.Begin () негарантированный немедленный запуск анимации: иногда это происходит при обратном вызове диспетчера.

С вами происходит то, что при первом запуске вашей раскадровки stb.Begin () планирует обратный вызов диспетчера для запуска анимациии сразу же возвращается.Следующие четыре строки вашего кода обновляют значения:

News1.Center = new Point(250, 400);      
News1.Orientation = 0;      
News1.Width = 266;      
News1.Height = 400;

Когда анимации фактически запускаются в обратном вызове диспетчера, они видят новые значения и используют их в качестве своих начальных значений.Это приводит к тому, что объект, кажется, сразу переходит к новому значению.

Например, changeWidth объявляет ключевой кадр, который анимирует значение до 266:

changeWidth.KeyFrames.Add(new EasingDoubleKeyFrame(266, ...

И позже начальная ширина устанавливается на266:

News1.Width = 266;

Таким образом, если раскадровка начинается с задержкой, ширина будет меняться от 266 до 266. Другими словами, она не изменится.Если позже вы используете другую анимацию, чтобы изменить News1.Width на значение, отличное от 266, а затем запустите анимацию changeWidth, она будет работать.

Ваша анимация moveCenter работает надежно, поскольку она фактически устанавливает значение From в текущее значение:

moveCenter.From = News1.ActualCenter;    
moveCenter.To = new Point(250, 400);

Таким образом, анимация всегда начинается в старом центре, даже если News1.Center = new Point(250,400) после запуска анимации.

Решение

Так же, как вы установили «От» в PointAnimation, вы также можете установить начальное значение в других ваших анимациях.Это делается путем добавления ключевого кадра в момент времени 0 с указанием текущей ширины:

changeWidth.Duration = TimeSpan.FromSeconds(1);
changeWidth.KeyFrames.Add(new DiscreteDoubleKeyframe(News1.Width, KeyTime.Paced));
changeWidth.KeyFrames.Add(new EasingDoubleKeyFrame(266, KeyTime.Paced));

Этот код использует тот факт, что KeyTime.Paced автоматически приводит к 0% и 100%, если есть два ключевых кадра.Фактически, установка первого кадра как KeyFrame.Paced всегда будет эквивалентна KeyTime.FromTimeSpan(TimeSpan.Zero).

0 голосов
/ 17 апреля 2012

Другим решением может быть использование FillBehavior.HoldEnd, затем подключение к событию Storyboard.Completed и:

  • Установка локальных значений, как вы изначально делали
  • Вызов Storyboard.Remove

Это также будет иметь преимущество в том, что локальные значения будут доступны из свойств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...