Blend KeyTrigger 多次触发
我在 WPF 项目中使用 Blend SDK KeyTrigger,并且遇到这样的问题:每次按下指定的键(此处为 DeleteCommand)时,都会多次触发该事件。
<ei:KeyTrigger FiredOn="KeyDown" ActiveOnFocus="True" SourceName="repositoryPackages" Key="Delete">
<i:InvokeCommandAction Command="{Binding SelectedItem.DeleteCommand, repositoryPackages}" />
</ei:KeyTrigger>
该触发器位于 ListView 的触发器集合中,ListView 本身位于用户控件内的网格上。
然后,用户控件将嵌入到应用程序主窗口上的 WPF TabControl 的选项卡上。
每次我用 ListView 切换回选项卡时,触发器都会无限次地调用该命令。
我查看了 KeyTrigger 的源代码(在 Microsoft.Expressions.Interactions 中),并注意到以下几行:
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?
I am using the Blend SDK KeyTrigger in a WPF project and have the problem that the event is fired multiple times each time I press the assigned key, here the DeleteCommand.
<ei:KeyTrigger FiredOn="KeyDown" ActiveOnFocus="True" SourceName="repositoryPackages" Key="Delete">
<i:InvokeCommandAction Command="{Binding SelectedItem.DeleteCommand, repositoryPackages}" />
</ei:KeyTrigger>
This trigger is in the trigger collection of a ListView which itself is on a grid inside a user control.
The user control is then embedded on a tab of a WPF TabControl on the application main window.
Each time I switch away and back to the tab with my ListView the trigger invokes the command one more time ad infinitum.
I looked at the source of KeyTrigger (in Microsoft.Expressions.Interactions) and noticed the following lines:
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);
}
}
The OnEvent method gets called once for each time the associated element of the trigger gets an OnLoaded event. But elements on a TabControl get an OnLoaded event each time you activate a tab. Which means you add the same event handler to KeyDown/KeyUp each time.
For me this really looks like a big oversight in the implementation of Blend SDK KeyTrigger.
Does anyone have an idea to prevent this or probably how to implement a correct KeyTrigger?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您是否尝试过使用
FiredOn="KeyUp"
来代替? KeyDown 也可以被操作系统重复,我想你无论如何也不希望重复删除?Have you tried using
FiredOn="KeyUp"
instead? KeyDown can be repeated by the OS too and I presume you don't want repeated delete anyway?KeyTrigger 在 Loaded 事件上注册 KeyDown/Up 事件。
例如,在选项卡控件中,当您切换到另一个选项卡时,您会收到 Unloaded 事件,而当您返回选项卡时,您会再次收到 Loaded 事件。这会导致再次注册 keydown/up 事件。
这似乎是微软的一个错误,因为我认为他们应该取消注册卸载事件!
我们之前已经看到过 KeyTrigger 导致内存泄漏,因为主窗口可能引用了已加载的选项卡,即使它被关闭/从选项卡控件中删除,它仍然被引用。
我的建议是将 CallMethodAction 与 KeyDown 事件一起使用。
KeyTrigger registers te KeyDown/Up events on the Loaded event.
In tab controls for example, when you switch to another tab, you get unloaded event, and when you get back to your tab you get a Loaded event again. This causes the registeration of the keydown/up events again.
This seem to be a bug of microsoft since I would thing that they should unregister the events on unload!!!
We have seen it before that KeyTrigger caused Memory Leaks since the main window might have a reference to the Tab that was loaded, and even when it was closed/removed from the tab control then it is still being referenced.
My suggest is to use CallMethodAction with KeyDown event.