2016-11-21 4 views
2

Я пытаюсь программным образом инициировать цветную анимацию на кнопке, но получаю System.InvalidOperationException, когда я это делаю. Кажется, он не может разрешить TargetProperty, потому что я создал кнопку, используя презентатор шаблона/контента.InvalidOperationException при попытке оживить цвет фона стилизованной кнопки в WPF

Причина, по которой я придерживаюсь стиля <Button>, заключается в том, чтобы заставить стиль быть последовательным (и избегать эффекта синего наведения по умолчанию). У меня также есть DataTrigger, который анимирует цвет фона этой кнопки всякий раз, когда он отображается (т. Е. Сделал видимым). Вот полный <Style> определение:

<Style x:Key="PopUnder" TargetType="Button"> 
    <Setter Property="Foreground" Value="Black" /> 
    <Setter Property="FontSize" Value="34" /> 
    <Setter Property="FontWeight" Value="SemiBold" /> 
    <Setter Property="OverridesDefaultStyle" Value="True" /> 
    <Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="Button"> 
     <Border Name="Border" Background="White" BorderBrush="Red" BorderThickness="0,1,0,1"> 
      <TextBlock TextWrapping="Wrap" TextAlignment="Center" VerticalAlignment="Center" LineStackingStrategy="BlockLineHeight" LineHeight="40" Text="{TemplateBinding Content}" /> 
     </Border> 
     <ControlTemplate.Triggers> 
      <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Visibility}" Value="Visible"> 
      <DataTrigger.EnterActions> 
       <BeginStoryboard> 
       <Storyboard> 
        <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" RepeatBehavior="Forever"> 
        <LinearColorKeyFrame Value="White" KeyTime="0:0:0" /> 
        <LinearColorKeyFrame Value="LightCoral" KeyTime="0:0:1" /> 
        <LinearColorKeyFrame Value="White" KeyTime="0:0:2" /> 
        </ColorAnimationUsingKeyFrames> 
       </Storyboard> 
       </BeginStoryboard> 
      </DataTrigger.EnterActions> 
      </DataTrigger> 
     </ControlTemplate.Triggers> 
     </ControlTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

Но я также хочу, чтобы иметь возможность запускать различные анимации на этой же кнопке, с помощью кода. Поэтому у меня есть отдельный <Storyboard>, определенный в другом месте (вне определения стиля), который я запускаю с использованием TryFindResource() ... Begin(). Однако, поскольку кнопка использует шаблон, у меня возникла проблема с тем, чтобы свойство цвета фона было правильно разрешено в моем XAML (см. Ниже).

<Storyboard x:Key="StatusGood" Completed="AnimationStatusGood_Completed"> 
    <ColorAnimationUsingKeyFrames Storyboard.TargetName="PopUnderMessage" Storyboard.TargetProperty="(Border).(Background).(SolidColorBrush.Color)"> 
     <LinearColorKeyFrame Value="LightGreen" KeyTime="0:0:0" /> 
     <LinearColorKeyFrame Value="White" KeyTime="0:0:1" /> 
    </ColorAnimationUsingKeyFrames> 
</Storyboard> 

Я пытался несколько различных значений для атрибута Storyboard.TargetProperty здесь:

  • (Background) (SolidColorBrush.Color)
  • (Border) (Background) (SolidColorBrush... .Color)
  • (Border.Background). (SolidColorBrush.Color)

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

ответ

0

Попробуйте это, опуская Storyboard.TargetName целиком, и опуская Border из Storyboard.TargetProperty:

<Storyboard x:Key="StatusGood" Completed="AnimationStatusGood_Completed"> 
    <ColorAnimationUsingKeyFrames 
     Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"> 
     <LinearColorKeyFrame Value="LightGreen" KeyTime="0:0:0" /> 
     <LinearColorKeyFrame Value="White" KeyTime="0:0:1" /> 
    </ColorAnimationUsingKeyFrames> 
</Storyboard> 

Дайте стилизованную кнопку имя:

<Button 
    x:Name="button" 
    Content="Hello, world!" 
    Style="{StaticResource PopUnder}" Click="ButtonBase_OnClick" /> 

Для активации раскадровку:

private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
{ 
    Storyboard storyboard = (Storyboard)this.TryFindResource("StatusGood"); 
    Border border = FindVisualChild<Border>(button, "Border"); 
    storyboard.Begin(border); 
} 

Для справки, FindVisualChild вспомогательная функция:

private static T FindVisualChild<T>(
    DependencyObject parent, 
    string name = null) 
    where T : DependencyObject 
{ 
    if (parent != null) 
    { 
     int childrenCount = VisualTreeHelper.GetChildrenCount(parent); 
     for (int i = 0; i < childrenCount; i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(parent, i); 
      T candidate = child as T; 
      if (candidate != null) 
      { 
       if (name == null) 
       { 
        return candidate; 
       } 

       FrameworkElement element = candidate as FrameworkElement; 
       if (name == element?.Name) 
       { 
        return candidate; 
       } 
      } 

      T childOfChild = FindVisualChild<T>(child, name); 
      if (childOfChild != null) 
      { 
       return childOfChild; 
      } 
     } 
    } 

    return default(T); 
} 
Смежные вопросы