首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Blend KeyTrigger多次触发

Blend KeyTrigger多次触发
EN

Stack Overflow用户
提问于 2011-05-10 17:44:09
回答 2查看 2K关注 0票数 3

我在一个WPF项目中使用Blend SDK KeyTrigger,每次我按下指定的键,这里是DeleteCommand,就会多次触发该事件。

代码语言:javascript
复制
<ei:KeyTrigger FiredOn="KeyDown" ActiveOnFocus="True" SourceName="repositoryPackages" Key="Delete">
  <i:InvokeCommandAction Command="{Binding SelectedItem.DeleteCommand, repositoryPackages}" />
</ei:KeyTrigger>

此触发器位于ListView的trigger集合中,而trigger集合本身位于用户控件内的网格上。

然后,将用户控件嵌入到应用程序主窗口上的WPF TabControl的选项卡上。

每次我使用ListView切换到选项卡时,触发器都会再次无限地调用该命令。

我查看了KeyTrigger的源代码(在Microsoft.Expressions.Interactions中),并注意到以下几行:

代码语言:javascript
复制
protected override void OnEvent(EventArgs eventArgs)
{
  if (this.ActiveOnFocus)
  {
    this.targetElement = base.Source;
  }
  else
  {
    this.targetElement = GetRoot(base.Source);
  }
  if (this.FiredOn == KeyTriggerFiredOn.KeyDown)
  {
    this.targetElement.KeyDown += new KeyEventHandler(this.OnKeyPress);
  }
  else
  {
    this.targetElement.KeyUp += new KeyEventHandler(this.OnKeyPress);
  }
}

每当触发器的关联元素获取OnLoaded事件时,都会调用一次OnEvent方法。但每次激活选项卡时,TabControl上的元素都会获得一个OnLoaded事件。这意味着您每次都要向KeyDown/KeyUp添加相同的事件处理程序。

对我来说,这看起来真的是Blend SDK KeyTrigger实现中的一个很大的疏忽。

有没有人有办法防止这种情况发生,或者是如何实现正确的KeyTrigger?

EN

回答 2

Stack Overflow用户

发布于 2011-05-10 17:48:53

您是否尝试过使用FiredOn="KeyUp"?KeyDown也可以被操作系统重复,我想你也不想重复删除吧?

票数 2
EN

Stack Overflow用户

发布于 2012-01-12 20:49:05

KeyTrigger在已加载的事件上注册te向下/向上键事件。

代码语言:javascript
复制
    public class KeyTrigger : EventTriggerBase<UIElement>
{
    // Fields
    public static readonly DependencyProperty ActiveOnFocusProperty = DependencyProperty.Register("ActiveOnFocus", typeof(bool), typeof(KeyTrigger));
    public static readonly DependencyProperty FiredOnProperty = DependencyProperty.Register("FiredOn", typeof(KeyTriggerFiredOn), typeof(KeyTrigger));
    public static readonly DependencyProperty KeyProperty = DependencyProperty.Register("Key", typeof(Key), typeof(KeyTrigger));
    public static readonly DependencyProperty ModifiersProperty = DependencyProperty.Register("Modifiers", typeof(ModifierKeys), typeof(KeyTrigger));
    private UIElement targetElement;

    // Methods
    private static ModifierKeys GetActualModifiers(Key key, ModifierKeys modifiers)
    {
        if ((key == Key.LeftCtrl) || (key == Key.RightCtrl))
        {
            modifiers |= ModifierKeys.Control;
            return modifiers;
        }
        if (((key == Key.LeftAlt) || (key == Key.RightAlt)) || (key == Key.System))
        {
            modifiers |= ModifierKeys.Alt;
            return modifiers;
        }
        if ((key == Key.LeftShift) || (key == Key.RightShift))
        {
            modifiers |= ModifierKeys.Shift;
        }
        return modifiers;
    }

    protected override string GetEventName()
    {
        return "Loaded";
    }

    private static UIElement GetRoot(DependencyObject current)
    {
        UIElement element = null;
        while (current != null)
        {
            element = current as UIElement;
            current = VisualTreeHelper.GetParent(current);
        }
        return element;
    }

    protected override void OnDetaching()
    {
        if (this.targetElement != null)
        {
            if (this.FiredOn == KeyTriggerFiredOn.KeyDown)
            {
                this.targetElement.KeyDown -= new KeyEventHandler(this.OnKeyPress);
            }
            else
            {
                this.targetElement.KeyUp -= new KeyEventHandler(this.OnKeyPress);
            }
        }
        base.OnDetaching();
    }

    protected override void OnEvent(EventArgs eventArgs)
    {
        if (this.ActiveOnFocus)
        {
            this.targetElement = base.Source;
        }
        else
        {
            this.targetElement = GetRoot(base.Source);
        }
        if (this.FiredOn == KeyTriggerFiredOn.KeyDown)
        {
            this.targetElement.KeyDown += new KeyEventHandler(this.OnKeyPress);
        }
        else
        {
            this.targetElement.KeyUp += new KeyEventHandler(this.OnKeyPress);
        }
    }

    private void OnKeyPress(object sender, KeyEventArgs e)
    {
        if ((e.Key == this.Key) && (Keyboard.Modifiers == GetActualModifiers(e.Key, this.Modifiers)))
        {
            base.InvokeActions(e);
        }
    }

    // Properties
    public bool ActiveOnFocus
    {
        get
        {
            return (bool)base.GetValue(ActiveOnFocusProperty);
        }
        set
        {
            base.SetValue(ActiveOnFocusProperty, value);
        }
    }

    public KeyTriggerFiredOn FiredOn
    {
        get
        {
            return (KeyTriggerFiredOn)base.GetValue(FiredOnProperty);
        }
        set
        {
            base.SetValue(FiredOnProperty, value);
        }
    }

    public Key Key
    {
        get
        {
            return (Key)base.GetValue(KeyProperty);
        }
        set
        {
            base.SetValue(KeyProperty, value);
        }
    }

    public ModifierKeys Modifiers
    {
        get
        {
            return (ModifierKeys)base.GetValue(ModifiersProperty);
        }
        set
        {
            base.SetValue(ModifiersProperty, value);
        }
    }
}

例如,在选项卡控件中,当您切换到另一个选项卡时,您将获得已卸载的事件,当您返回到您的选项卡时,您将再次获得已加载的事件。这会导致再次注册keydown/up事件。

这似乎是微软的一个bug,因为我认为他们应该在卸载时注销事件!

在KeyTrigger导致内存泄漏之前,我们已经看到过这种情况,因为主窗口可能有对加载的选项卡的引用,甚至当它被关闭/从选项卡控件中移除时,它仍然被引用。

我的建议是在KeyDown事件中使用CallMethodAction。

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

https://stackoverflow.com/questions/5948158

复制
相关文章

相似问题

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