2012-06-12 3 views
5

Как я могу анимировать ширину элемента от 0 до его фактической ширины в WPF?Ширина анимации до фактической ширины в WPF?

Я попытался это:

<ControlTemplate.Triggers> 
    <EventTrigger RoutedEvent="Loaded"> 
     <BeginStoryboard> 
      <Storyboard> 
       <DoubleAnimation Duration="0:0:0.3" To="{Binding ElementName=MyElement, Path=ActualWidth}" From="0" Storyboard.TargetProperty="Width" Storyboard.TargetName="MyElement" /> 
      </Storyboard> 
     </BeginStoryboard> 
    </EventTrigger> 
</ControlTemplate.Triggers> 

Если изменить привязку к жестко закодированного значения, как 100, то ширина правильно анимированные, за исключением того, что я хочу, чтобы привязать к фактической ширине элемента.

Если это имеет значение, MyElement - это граница, и я анимация элемента табуляции.

Для записи, это не работает, либо:

To="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}" 

ответ

9

Я уверен, что это неправильно по многим причинам, и, пожалуйста, не стесняйтесь рассказать мне, сколько законов WPF я нарушил, но .. Я решил ту же проблему, создав собственную BindableDoubleAnimation.

public class BindableDoubleAnimation : DoubleAnimationBase 
{ 
    DoubleAnimation internalAnimation; 

    public DoubleAnimation InternalAnimation { get { return internalAnimation; } } 

    public double To 
    { 
     get { return (double)GetValue(ToProperty); } 
     set { SetValue(ToProperty, value); } 
    } 

    /// <summary> 
    /// Dependency backing property for the <see cref="To"/> property. 
    /// </summary> 
    public static readonly DependencyProperty ToProperty = 
     DependencyProperty.Register("To", typeof(double), typeof(BindableDoubleAnimation), new UIPropertyMetadata(0d, new PropertyChangedCallback((s, e) => 
      { 
       BindableDoubleAnimation sender = (BindableDoubleAnimation)s; 
       sender.internalAnimation.To = (double)e.NewValue; 
      }))); 


    public double From 
    { 
     get { return (double)GetValue(FromProperty); } 
     set { SetValue(FromProperty, value); } 
    } 

    /// <summary> 
    /// Dependency backing property for the <see cref="From"/> property. 
    /// </summary> 
    public static readonly DependencyProperty FromProperty = 
     DependencyProperty.Register("From", typeof(double), typeof(BindableDoubleAnimation), new UIPropertyMetadata(0d, new PropertyChangedCallback((s, e) => 
     { 
      BindableDoubleAnimation sender = (BindableDoubleAnimation)s; 
      sender.internalAnimation.From = (double)e.NewValue; 
     }))); 


    public BindableDoubleAnimation() 
    { 
     internalAnimation = new DoubleAnimation(); 
    } 

    protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue, AnimationClock animationClock) 
    { 
     return internalAnimation.GetCurrentValue(defaultOriginValue, defaultDestinationValue, animationClock); 
    } 

    protected override Freezable CreateInstanceCore() 
    { 
     return internalAnimation.Clone();; 
    } 
} 

Теперь я могу использовать привязки для свойств To From.

<local:BindableDoubleAnimation Storyboard.TargetProperty="Width" From="0" To="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Window}}"/> 
+0

Кто-нибудь получил это, чтобы работать для 'BindableDoubleAnimation', которые находятся внутри' Storyboard', который находится в 'VisualState'' ControlTemplate'? Для случаев, когда у меня есть только одна «BindableDoubleAnimation» в «VisualState», а я жестко задаю значение «Кому» (чтобы сказать что-то вроде «100»), ничего не анимируется, и ни «GetCurrentValueCore», ни «CreateInstanceCore» не вызываются , В случаях, когда я использую привязку данных к свойству «To», привязка всегда терпит неудачу, всегда выдает ошибку «Невозможно найти источник для привязки ...». Даже когда я пробую все сверху дословно, он терпит неудачу. –

+0

... Я бы хотел, чтобы это сработало - похоже, это отличное решение! –

2

что привязок не могут быть использованы в анимации является общей проблемой.

Один из способов будет использовать вспомогательный объект, который имеет SourceValue & TargetValue (который вы можете связать все, что вы хотите, в том числе ActualWidth) а CurrentValue (который возвращает анимированное значение) и Progress, которые могут быть анимированными от 0,0 до 100,0. Когда прогресс будет изменен, вам просто нужно вычислить CurrentValue, к которому вы можете привязать Width вашего объекта. Это некрасиво, но должно работать.

+0

Я не совсем понял этот ответ. Не могли бы вы предоставить образец кода? Вы описываете что-то подобное решению @ Andy? –

+0

@PhillipScottGivens: ответ Энди всегда изменяет анимацию, создавая на ней слой с возможностью связывания. Я предлагаю другое, я предлагаю промежуточный объект, который всегда использует ту же анимацию, которая анимирует свойство 'Progress' от' 0' до '100' (при этом анимация не изменяется), этот объект предоставляет значение анимации через' CurrentValue', которое возвращает значение, вычисленное из его «SourceValue», «TargetValue» и «Progress». –

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