首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何给出EventTrigger的条件?

如何给出EventTrigger的条件?
EN

Stack Overflow用户
提问于 2010-05-04 18:17:11
回答 6查看 24K关注 0票数 21

可以在EventTrigger中给出条件吗?我已经为单选按钮写了下面的EventTrigger (Mouse.MouseLeave)。我希望不应为处于选中状态(IsChecked=True)的项目触发此操作。

代码语言:javascript
运行
复制
<EventTrigger RoutedEvent="Mouse.MouseLeave" SourceName="border">                                 
      <BeginStoryboard Name="out_BeginStoryboard" Storyboard="{StaticResource out}" />
      <RemoveStoryboard BeginStoryboardName="over_BeginStoryboard" />
</EventTrigger>

请告诉我如何才能做到这一点?

提前谢谢。

EN

回答 6

Stack Overflow用户

发布于 2010-05-13 06:52:50

您不能以这种方式使用EventTrigger。调用EventTriggers的WPF的RoutedEventHandler没有提供任何机制来使触发器成为条件触发器,而且您不能通过将TriggerAction子类化来解决这个问题,因为没有要覆盖的受保护的Invoke()或Execute()操作。

但是,使用自定义类可以很容易地完成这一点。下面是它的用法:

代码语言:javascript
运行
复制
<Border>
  <my:ConditionalEventTrigger.Triggers>
    <my:ConditionalEventTriggerCollection>
      <my:ConditionalEventTrigger RoutedEvent="Mouse.MouseLeave"
                                  Condition="{Binding IsChecked, ElementName=checkbox}">
        <BeginStoryboard Name="out_BeginStoryboard" Storyboard="{StaticResource out}" />               
        <RemoveStoryboard BeginStoryboardName="over_BeginStoryboard" />               
      </my:ConditionalEventTrigger>               
    </my:ConditionalEventTriggerCollection>
  </my:ConditionalEventTrigger.Triggers>
  ...

下面是它的实现方式:

代码语言:javascript
运行
复制
[ContentProperty("Actions")] 
public class ConditionalEventTrigger : FrameworkContentElement
{ 
  public RoutedEvent RoutedEvent { get; set; } 
  public List<TriggerAction> Actions { get; set; }

  // Condition
  public bool Condition { get { return (bool)GetValue(ConditionProperty); } set { SetValue(ConditionProperty, value); } }
  public static readonly DependencyProperty ConditionProperty = DependencyProperty.Register("Condition", typeof(bool), typeof(ConditionalEventTrigger));

  // "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)));
    } 
  });

  public ConditionalEventTrigger()
  {
    Actions = new List<TriggerAction>();
  }

  // When an event fires, check the condition and if it is true fire the actions 
  void OnRoutedEvent(FrameworkElement element) 
  { 
    DataContext = element.DataContext;  // Allow data binding to access element properties
    if(Condition) 
    { 
      // 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); 
      } 
    } 
  } 

  static RoutedEvent _triggerActionsEvent = EventManager.RegisterRoutedEvent("", RoutingStrategy.Direct, typeof(EventHandler), typeof(ConditionalEventTrigger)); 

} 

// Create collection type visible to XAML - since it is attached we cannot construct it in code 
public class ConditionalEventTriggerCollection : List<ConditionalEventTrigger> {} 

享受吧!

票数 24
EN

Stack Overflow用户

发布于 2010-11-14 22:43:35

这就是对我有效的..。

我想要基于鼠标悬停在UI元素上并且UI元素的相关所有者处于活动状态(即启用以使玩家移动)来执行动画。

为了支持这些需求,我使用了相对源代码绑定来克服缺乏对事件触发条件的支持。

示例:

代码语言:javascript
运行
复制
<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding RelativeSource={RelativeSource self}, Path=IsMouseOver}" Value="True" />
        <Condition Binding="{Binding Path=IsPlayer1Active}" Value="True" />
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.EnterActions>
        <BeginStoryboard>
            <Storyboard>
                <ColorAnimation Storyboard.TargetProperty="Background.GradientStops[0].Color" To="#FF585454" Duration="0:0:.25"/>
                <ColorAnimation Storyboard.TargetProperty="Background.GradientStops[1].Color" To="Black" Duration="0:0:2"/>
            </Storyboard>
        </BeginStoryboard>
    </MultiDataTrigger.EnterActions>
</MultiDataTrigger>
票数 11
EN

Stack Overflow用户

发布于 2010-08-05 04:48:55

这是我修改过的Ray's answer版本,它只在设置了源触发器时创建和附加虚拟事件,而不是每次都这样做。我认为这对于我的场景会更好,因为我正在发起一个关于数百个项目的事件,而不仅仅是一两个:

代码语言:javascript
运行
复制
[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<TriggerAction>();
    }

    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<TriggerAction> 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<DummyEventTrigger>().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 => 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) => {
                if (t.Condition) // evaluate condition when the event gets fired
                    targetObj.RaiseEvent(new RoutedEventArgs(DummyEvent));
            }));
        }
    }

    class DummyEventTrigger : EventTrigger { }
}

public class ConditionalEventTriggers : List<ConditionalEventTrigger> { }

它的用法如下:

代码语言:javascript
运行
复制
<Border>
  <local:ConditionalEventTrigger.Triggers>
    <local:ConditionalEventTriggers>
      <local:ConditionalEventTrigger RoutedEvent="local:ClientEvents.Flash" Condition="{Binding IsFlashing}">
        <BeginStoryboard Name="FlashAnimation">...

这条线

代码语言:javascript
运行
复制
// targetObj.GetDataContextChanged().WeakSubscribe(dc => t.DataContext = targetObj.DataContext);

使用反应式框架和我编写的一些扩展方法,基本上我们需要订阅目标对象的.DataContextChanged事件,但我们需要使用弱引用。如果您的对象从来不更改它们的datacontext,那么您根本就不需要这些代码

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2764415

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档