2016-04-06 3 views
0

У меня есть StackPanel с несколькими кнопками. Я хочу, чтобы все кнопки, кроме одного, чтобы вызвать анимацию, когда пользователь нажимает на них, так что в StackPanel.Triggers я добавил этот код:В WPF, как переопределить триггер событий?

<StackPanel.Triggers> 
    <EventTrigger RoutedEvent="Button.Click"> 
     <BeginStoryboard Storyboard="{StaticResource animationName}" /> 
    </EventTrigger> 
</StackPanel.Triggers> 

В частности, кнопки я добавил этот код:

<Button.Triggers> 
    <EventTrigger RoutedEvent="Button.Click"> 
     <BeginStoryboard Storyboard="{StaticResource anotherAnimation}" /> 
    </EventTrigger> 
</Button.Triggers> 

При нажатии кнопки начинаются обе анимации, поэтому оказывается, что второй EventTrigger просто добавлен к первому, а не переопределяет его.

Как я могу переопределить первый EventTrigger, так что только второй будет срабатывать при нажатии на эту конкретную кнопку?

Примечание: Мне нужен ответ, чтобы быть в чистом XAML без какого-либо кода.


EDIT: Вот раскадровка:

<Storyboard x:Key="animationName"> 
    <DoubleAnimation 
     Storyboard.TargetName="PageFrame" 
     Storyboard.TargetProperty="Opacity" 
     To="0" Duration="0:0:0.25" /> 
</Storyboard> 
+0

Я очень новичок в WPF, поэтому более чем вероятно, что это глупый вопрос. Однако я был бы признателен за серьезный ответ. Также, извините за мой английский, если это не очень хорошо. :) Я попытался изо всех сил объяснить свою проблему, надеюсь, что вы могли бы мне помочь – Sipo

ответ

3

Просто используйте x:Key свойство для необходимых кнопок. Например:

<Window> 
    <Window.Resources> 
     <Style x:Key="myStyle" TargetType="Button"> 
      <Setter Property="Background" Value="Green"/> 
      <Style.Triggers> 
      <EventTrigger RoutedEvent="Button.Click"> 
    <BeginStoryboard Storyboard="{StaticResource animationName}" /> 
      </EventTrigger> 
      </Style.Triggers> 
     </Style> 
    </Window.Resources> 

    <StackPanel Orientation="Horizontal" VerticalAlignment="Top"> 
     <Button Style="{StaticResource myStyle}">Styles are cool!</Button> 
     <Button>No Animation:)</Button> 
     <Button Style="{StaticResource myStyle}">Yes to animation!</Button> 
    </StackPanel> 
</Window> 

Update:

Если вы хотите, чтобы избежать использования Style всего несколько кнопок, просто создать стиль для всех Button управления и установить Style="{x:Null}" для управления, где вы хотите, чтобы избежать анимации. Смотрите следующий пример:

<Window> 
    <Window.Resources> 
     <!--This style will be applied to all Buttons, except where Style="{x:Null}"--> 
     <Style TargetType="Button"> 
      <Style.Resources> 
      <Storyboard x:Key="animationName"> 
       <DoubleAnimation Storyboard.TargetProperty="Opacity" 
    To="0" Duration="0:0:0.25" /> 
      </Storyboard> 
     </Style.Resources> 
      <Setter Property="Background" Value="Green"/> 
      <Style.Triggers> 
      <EventTrigger RoutedEvent="Button.Click"> 
    <BeginStoryboard Storyboard="{StaticResource animationName}" /> 
      </EventTrigger> 
      </Style.Triggers> 
     </Style> 
    </Window.Resources> 

    <StackPanel Orientation="Horizontal" VerticalAlignment="Top"> 
     <Button Content="Yes to Animation"/> 
     <Button Content="No Animation:)" Style="{x:Null}"/> 
     <Button Content="Yes to Animation"/> 
    </StackPanel> 
</Window> 

Update 1:

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

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

+0

Спасибо. Очень хорошая идея. Но, поскольку у меня много кнопок, очень сложно писать атрибут 'Style' для каждого. Есть ли способ сделать его более общим, а не для каждой из кнопок? Спасибо большое! – Sipo

+0

@ Рубен - не могли бы вы продемонстрировать в ответ? Большое спасибо! – Sipo

+0

Кроме того, это не сработает для меня, потому что в раскадровке есть TargeName, поэтому он не может быть в стиле, я думаю ... – Sipo

2

Как и было обещано, я принял @RayBurns ответ из этого link и изменил его, чтобы ответить на ваш вопрос. ConditionalEventTrigger сейчас выглядит так:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows; 
using System.Windows.Markup; 

namespace Trigger 
{ 
[ContentProperty("Actions")] 
public class ConditionalEventTrigger : FrameworkContentElement 
{ 
    private static readonly RoutedEvent TriggerActionsEvent = EventManager.RegisterRoutedEvent("", RoutingStrategy.Direct, typeof(EventHandler), typeof(ConditionalEventTrigger)); 
    public RoutedEvent RoutedEvent { get; set; } 

    public static readonly DependencyProperty ExcludedSourceNamesProperty = DependencyProperty.Register(
     "ExcludedSourceNames", typeof (List<string>), typeof (ConditionalEventTrigger), new PropertyMetadata(new List<string>())); 

    public List<string> ExcludedSourceNames 
    { 
     get { return (List<string>) GetValue(ExcludedSourceNamesProperty); } 
     set { SetValue(ExcludedSourceNamesProperty, value); } 
    } 

    public static readonly DependencyProperty ActionsProperty = DependencyProperty.Register(
     "Actions", typeof (List<TriggerAction>), typeof (ConditionalEventTrigger), new PropertyMetadata(new List<TriggerAction>())); 

    public List<TriggerAction> Actions 
    { 
     get { return (List<TriggerAction>) GetValue(ActionsProperty); } 
     set { SetValue(ActionsProperty, value); } 
    } 

    // "Triggers" attached property 
    public static ConditionalEventTriggerCollection GetTriggers(DependencyObject obj) { return (ConditionalEventTriggerCollection)obj.GetValue(TriggersProperty); } 
    public static void SetTriggers(DependencyObject obj, ConditionalEventTriggerCollection value) { obj.SetValue(TriggersProperty, value); } 
    public static readonly DependencyProperty TriggersProperty = DependencyProperty.RegisterAttached("Triggers", typeof(ConditionalEventTriggerCollection), typeof(ConditionalEventTrigger), new PropertyMetadata 
    { 
     PropertyChangedCallback = (obj, e) => 
     { 
      // When "Triggers" is set, register handlers for each trigger in the list 
      var element = (FrameworkElement)obj; 
      var triggers = (List<ConditionalEventTrigger>)e.NewValue; 
      foreach (var trigger in triggers) 
       element.AddHandler(trigger.RoutedEvent, new RoutedEventHandler((obj2, e2) => 
        trigger.OnRoutedEvent(element, e2))); 
     } 
    }); 



    // When an event fires, check the condition and if it is true fire the actions 
    void OnRoutedEvent(FrameworkElement element, RoutedEventArgs args) 
    { 
     var originalSender = args.OriginalSource as FrameworkElement; 
     if(originalSender == null) return; 
     DataContext = element.DataContext; // Allow data binding to access element properties 
     if (!ExcludedSourceNames.Any(x=>x.Equals(originalSender.Name))) 
     { 
      // Construct an EventTrigger containing the actions, then trigger it 
      var dummyTrigger = new EventTrigger { RoutedEvent = TriggerActionsEvent }; 
      foreach (var action in Actions) 
       dummyTrigger.Actions.Add(action); 

      element.Triggers.Add(dummyTrigger); 
      try 
      { 
       element.RaiseEvent(new RoutedEventArgs(TriggerActionsEvent)); 
      } 
      finally 
      { 
       element.Triggers.Remove(dummyTrigger); 
      } 
     } 
    } 
} 

public class ConditionalEventTriggerCollection: List<ConditionalEventTrigger>{} 
} 

Он может быть использован в вашем XAML, как это. Позаботьтесь, чтобы все SourceNames вы не хотят быть признанными на выполнении ваших действий внутри секции ExcludedSourceNames .:

 <trigger:ConditionalEventTrigger.Triggers> 
     <trigger:ConditionalEventTriggerCollection> 
      <trigger:ConditionalEventTrigger RoutedEvent="Button.Click"> 
       <trigger:ConditionalEventTrigger.ExcludedSourceNames> 
        <system:String>buttonTriggeringAnotherAnimation</system:String> 
       </trigger:ConditionalEventTrigger.ExcludedSourceNames> 
       <BeginStoryboard Storyboard="{StaticResource Storyboard1}"></BeginStoryboard> 
      </trigger:ConditionalEventTrigger> 
     </trigger:ConditionalEventTriggerCollection> 
    </trigger:ConditionalEventTrigger.Triggers> 

дать вам готов начать пример здесь окно:

<Window x:Class="ConditionalEventTriggerExample.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:ConditionalEventTriggerExample" 
    xmlns:trigger="clr-namespace:Trigger;assembly=Trigger" 
    xmlns:system="clr-namespace:System;assembly=mscorlib" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.Resources> 
    <Storyboard x:Key="Storyboard1"> 
     <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="rectangle"> 
      <EasingColorKeyFrame KeyTime="0:0:1" Value="#FF5151FD"/> 
     </ColorAnimationUsingKeyFrames> 
    </Storyboard> 
    <Storyboard x:Key="Storyboard2"> 
     <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="rectangle1"> 
      <EasingColorKeyFrame KeyTime="0:0:1" Value="#FFFF7400"/> 
     </ColorAnimationUsingKeyFrames> 
    </Storyboard> 
</Window.Resources> 
<StackPanel> 
    <StackPanel.Triggers> 
     <EventTrigger RoutedEvent="Button.Click" SourceName="buttonTriggeringAnotherAnimation"> 
      <BeginStoryboard Storyboard="{StaticResource Storyboard2}"/> 
     </EventTrigger> 
    </StackPanel.Triggers> 
    <trigger:ConditionalEventTrigger.Triggers> 
     <trigger:ConditionalEventTriggerCollection> 
      <trigger:ConditionalEventTrigger RoutedEvent="Button.Click"> 
       <trigger:ConditionalEventTrigger.ExcludedSourceNames> 
        <system:String>buttonTriggeringAnotherAnimation</system:String> 
       </trigger:ConditionalEventTrigger.ExcludedSourceNames> 
       <BeginStoryboard Storyboard="{StaticResource Storyboard1}"></BeginStoryboard> 
      </trigger:ConditionalEventTrigger> 
     </trigger:ConditionalEventTriggerCollection> 
    </trigger:ConditionalEventTrigger.Triggers> 
    <Button x:Name="button" Content="Button"/> 
    <Button x:Name="button1" Content="Button"/> 
    <Button x:Name="buttonTriggeringAnotherAnimation" Content="triggering another animation"/> 
    <Button x:Name="button3" Content="Button"/> 
    <Button x:Name="button4" Content="Button"/> 
    <Button x:Name="button5" Content="Button"/> 
    <Rectangle x:Name="rectangle" Fill="#FFF4F4F5" Height="100" Stroke="Black"/> 
    <Rectangle x:Name="rectangle1" Fill="#FFF4F4F5" Height="100" Stroke="Black"/> 
</StackPanel> 

Если вы не получили его на работу, я могу загрузить решение на GitHub.

+0

Спасибо, но мне действительно нужен более простой ответ без кода. Большое вам спасибо за ваше время и инвестиции! – Sipo

+0

Это не кодовое слово. Это автономный класс, который позволяет использовать функции ConditionalEventTrigger. Вы можете разместить этот класс там, где хотите, до тех пор, пока вы ссылаетесь на него правильно в своем пространстве имен XAML ... – Nebelkraehe

+0

Хорошо, я попробую, и если он будет работать лучше, я выберу этот ответ! Благодаря! – Sipo

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