Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here's my modified version of <a href="https://stackoverflow.com/questions/2764415/how-to-give-the-condition-for-eventtrigger/2823333#2823333">Ray's answer</a>, which creates and attaches dummy events only when the source triggers are set, rather than doing it each time. I thought this would be better for my scenario as I am raising an event on hundreds of items, not just one or two:</p> <pre><code>[ContentProperty("Actions")] public class ConditionalEventTrigger : FrameworkContentElement { static readonly RoutedEvent DummyEvent = EventManager.RegisterRoutedEvent( "", RoutingStrategy.Direct, typeof(EventHandler), typeof(ConditionalEventTrigger)); public static readonly DependencyProperty TriggersProperty = DependencyProperty.RegisterAttached( "Triggers", typeof(ConditionalEventTriggers), typeof(ConditionalEventTrigger), new FrameworkPropertyMetadata(RefreshTriggers)); public static readonly DependencyProperty ConditionProperty = DependencyProperty.Register( "Condition", typeof(bool), typeof(ConditionalEventTrigger)); // the Condition is evaluated whenever an event fires public ConditionalEventTrigger() { Actions = new List&lt;TriggerAction&gt;(); } public static ConditionalEventTriggers GetTriggers(DependencyObject obj) { return (ConditionalEventTriggers)obj.GetValue(TriggersProperty); } public static void SetTriggers(DependencyObject obj, ConditionalEventTriggers value) { obj.SetValue(TriggersProperty, value); } public bool Condition { get { return (bool)GetValue(ConditionProperty); } set { SetValue(ConditionProperty, value); } } public RoutedEvent RoutedEvent { get; set; } public List&lt;TriggerAction&gt; Actions { get; set; } // --- impl ---- // we can't actually fire triggers because WPF won't let us (stupid sealed internal methods) // so, for each trigger, make a dummy trigger (on a dummy event) with the same actions as the real trigger, // then attach handlers for the dummy event public static void RefreshTriggers(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var targetObj = (FrameworkElement)obj; // start by clearing away the old triggers foreach (var t in targetObj.Triggers.OfType&lt;DummyEventTrigger&gt;().ToArray()) targetObj.Triggers.Remove(t); // create and add dummy triggers foreach (var t in ConditionalEventTrigger.GetTriggers(targetObj)) { t.DataContext = targetObj.DataContext; // set and Track DataContext so binding works // targetObj.GetDataContextChanged().WeakSubscribe(dc =&gt; t.DataContext = targetObj.DataContext); var dummyTrigger = new DummyEventTrigger { RoutedEvent = DummyEvent }; foreach (var action in t.Actions) dummyTrigger.Actions.Add(action); targetObj.Triggers.Add(dummyTrigger); targetObj.AddHandler(t.RoutedEvent, new RoutedEventHandler((o, args) =&gt; { if (t.Condition) // evaluate condition when the event gets fired targetObj.RaiseEvent(new RoutedEventArgs(DummyEvent)); })); } } class DummyEventTrigger : EventTrigger { } } public class ConditionalEventTriggers : List&lt;ConditionalEventTrigger&gt; { } </code></pre> <p>It's used like this:</p> <pre><code>&lt;Border&gt; &lt;local:ConditionalEventTrigger.Triggers&gt; &lt;local:ConditionalEventTriggers&gt; &lt;local:ConditionalEventTrigger RoutedEvent="local:ClientEvents.Flash" Condition="{Binding IsFlashing}"&gt; &lt;BeginStoryboard Name="FlashAnimation"&gt;... </code></pre> <p>The line</p> <pre><code>// targetObj.GetDataContextChanged().WeakSubscribe(dc =&gt; t.DataContext = targetObj.DataContext); </code></pre> <p>is using the reactive framework and some extension methods I wrote, basically we need to subscribe to the <code>.DataContextChanged</code> event of the target object, but we need to do it with a weak reference. If your objects don't ever change their datacontext, then you won't need this code at all</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload