2016-06-14 2 views
0

Я хочу запустить простую анимацию на картинке стрелки (png). Стрелка указывает либо вниз, либо вверх, и анимация должна быть волной, проходящей по стрелке в направлении, на которое она указывает.Раскадровка не меняется при изменении стиля в WPF

Я использую элемент управления Image и присваиваю ему один из двух стилей. Эти стили определяют изображение для использования и три двойные анимации в раскадровке. Предполагается, что анимация будет работать безоговорочно, только с момента создания изображения навсегда. Один из стилей - стрелка, направленная вверх, с волной, движущейся вверх (Trend_Rising), а другой стиль - стрелка, направленная вниз, с волной, идущей вниз (Trend_Falling).

Ниже приведено изображение, а стиль находится в отдельном файле, указанном в UserControl, где встроено изображение.

<Image x:Name="TrendImg" Style="{DynamicResource Trend_Falling}" /> 

Это содержимое файла стилей:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 

    <Style x:Key="Trend_Base" TargetType="Image"> 

     <Setter Property="OpacityMask"> 
      <Setter.Value> 
       <LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> 
        <GradientStop Color="Black" /> 
        <GradientStop Color="Transparent" /> 
        <GradientStop Color="Black" /> 
       </LinearGradientBrush> 
      </Setter.Value> 
     </Setter> 

    </Style> 

    <Style x:Key="Trend_Rising_Base" TargetType="Image" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="IsVisible" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0" To="1.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1" To="1.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Falling_Base" TargetType="Image" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="IsVisible" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Rising" TargetType="Image" BasedOn="{StaticResource Trend_Rising_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_rising.png" /> 
    </Style> 

    <Style x:Key="Trend_Falling" TargetType="Image" BasedOn="{StaticResource Trend_Falling_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_falling.png" /> 
    </Style> 

</ResourceDictionary> 

Дело в том, что, когда я изменить стиль программно, анимация не меняется. Например, если я запускаю приложение (у изображения есть назначенный стиль Trend_Falling), стрелка вниз будет отображаться с перемещением волновой анимации вниз. Но когда я меняю стиль на Trend_Rising во время выполнения, изображение стрелки меняется как следует, но анимация остается прежней.

TrendImg.SetResourceReference(Control.StyleProperty, "Trend_Rising") 

Что я делаю неправильно? Буду благодарен за любую помощь. Спасибо!

- EDIT -

Я создал ImageWithAnim класса, который является потомком Image, и добавил Animate свойства булева зависимости к нему. Затем я привязал триггер к этому свойству вместо IsVisible. Истина запускает раскадровку, и ложь должна остановить ее, но это не так ... Когда я установил Анимация в false, выдается исключение, говорящее, что имя RisingStoryboard не может быть разрешено в пространстве имен System.Windows .Style. Я нашел несколько сообщений в StackOverflow, согласно которым этот пример должен работать (среди тех, кто утверждал, что это не будет :-)).

Итак ... теперь я понятия не имею, как это сделать правильно. Буду благодарен за любую помощь. Спасибо!

Это измененная XAML:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Test="clr-namespace:StyleChangeTest"> 

    <Style x:Key="Trend_Base" TargetType="Test:ImageWithAnim"> 

     <Setter Property="OpacityMask"> 
      <Setter.Value> 
       <LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> 
        <GradientStop Color="Black" /> 
        <GradientStop Color="Transparent" /> 
        <GradientStop Color="Black" /> 
       </LinearGradientBrush> 
      </Setter.Value> 
     </Setter> 

    </Style> 

    <Style x:Key="Trend_Rising_Base" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="RisingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0" To="1.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1" To="1.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 

      <Trigger Property="Animate" Value="False"> 
       <Trigger.EnterActions> 
        <StopStoryboard BeginStoryboardName="RisingStoryboard" /> 
       </Trigger.EnterActions> 
      </Trigger> 
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Falling_Base" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="FallingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 

      <Trigger Property="Animate" Value="False"> 
       <Trigger.EnterActions> 
        <StopStoryboard BeginStoryboardName="FallingStoryboard" /> 
       </Trigger.EnterActions> 
      </Trigger>     
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Rising" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Rising_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_rising.png" /> 
    </Style> 

    <Style x:Key="Trend_Falling" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Falling_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_falling.png" /> 
    </Style> 

</ResourceDictionary> 

И вот ImageWithAnim класс:

Public Class ImageWithAnim 
    Inherits Image 

    Private Shared _animate As DependencyProperty = DependencyProperty.Register("Animate", 
                       GetType(Boolean), 
                       GetType(ImageWithAnim), 
                       New PropertyMetadata(defaultValue:=False)) 

    Public Shared ReadOnly Property AnimateProperty As DependencyProperty 
     Get 
      Return _animate 
     End Get 
    End Property 

    Public Property Animate() As Boolean 
     Get 
      Return CBool(GetValue(_animate)) 
     End Get 
     Set(value As Boolean) 
      SetValue(_animate, value) 
     End Set 
    End Property 

End Class 
+0

Вы нацеливаете только изображение TargetType. Поэтому все равно, что сам образ изменился, просто изображение есть. Если вы собираетесь идти по этому маршруту, то при изменении источника изображения вам нужно вручную остановить/начать обмен между отдельными анимациями. –

+0

Спасибо, @ChrisW., Но как бы вы остановили анимацию и перезапустили ее? Я знаю WPF в некоторой степени, но я не специалист. Можно ли это сделать простым способом, используя стиль, или это должно быть сделано программно? Первой идеей, которая приходит мне на ум, является создание потомка класса Image со свойством, определяющим, должна ли анимация запускаться или останавливаться. Затем используйте этот класс вместо изображения и присоедините его к этому свойству вместо IsVisible. Это хорошая идея или все можно сделать проще? –

+0

Я создал потомок изображения с логическим свойством зависимостей Animate. Я использовал его в стиле вместо IsVisible, и мне удалось запустить анимацию, установив Animate в True. Тем не менее, остановить его, установив Animate to False, не получилось. Поэтому я добавил второй триггер, прикрепленный к Animate = False, с элементом StopStoryboard, у которого значение BeginStoryBoardName установлено на x: Имя BeginStoryboard, определенное для Animate = True. Теперь каждый раз, когда я устанавливаю Animate для False, я получаю исключение, говоря, что указанное имя BeginStoryboard не может быть разрешено в пространстве имен System.Windows.Style. Я застрял. –

ответ

0

По совпадению я только что нашел ответ на свой вопрос. Имена раскадровки не могут быть решены, потому что они были определены в базовых стилях.Когда я определил их непосредственно в моих двух стилях интереса, я мог бы начать и остановить их, используя Анимация свойство ImageWithAnim как и ожидалось, без каких-либо исключений.

Таким образом, при изменении стиля изображения, я должен сделать следующее:

TrendImg.Animate = False 
TrendImg.SetResourceReference(ImageWithAnim.StyleProperty, "Trend_Falling") 
TrendImg.Animate = True 

Теперь анимация изменяется должным образом, и волна анимации движется в направлении стрелка указывает на, что чего я хотел достичь.

И вот измененный стиль:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Test="clr-namespace:StyleChangeTest"> 

    <Style x:Key="Trend_Base" TargetType="Test:ImageWithAnim"> 

     <Setter Property="OpacityMask"> 
      <Setter.Value> 
       <LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> 
        <GradientStop Color="Black" /> 
        <GradientStop Color="Transparent" /> 
        <GradientStop Color="Black" /> 
       </LinearGradientBrush> 
      </Setter.Value> 
     </Setter> 

    </Style> 

    <Style x:Key="Trend_Rising" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_rising.png" /> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="RisingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0" To="1.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1" To="1.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 

       <Trigger.ExitActions> 
        <StopStoryboard BeginStoryboardName="RisingStoryboard" /> 
       </Trigger.ExitActions> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

    <Style x:Key="Trend_Falling" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_falling.png" /> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="FallingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 

       <Trigger.ExitActions> 
        <StopStoryboard BeginStoryboardName="FallingStoryboard" /> 
       </Trigger.ExitActions> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

</ResourceDictionary> 

И объяснить, почему я раскадровки в базовых стилей в начале. Дело в том, что в моем оригинальном приложении у меня есть несколько разных изображений стрелок, и я просто не хотел повторять определения раскадровки. Но мне кажется, что я должен.

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