从菜单启动时,InputManager 会忽略剪切/复制/粘贴
我正在使用 InputManager 来检查对控件的更改是否是由用户或代码完成的。这工作正常,除非用户使用上下文菜单进行剪切/复制/粘贴。如果用户在文本框中执行 ctrl+v,InputManager 会正确注意到它。但是,如果从文本框的上下文菜单完成粘贴,则 InputManager 永远不会触发 PreNotifyInput 或 PostNotifyInput 事件。有人知道为什么吗?或者如何检测这些用户操作?下面是一个工作示例。当用户使用上面文本框中的剪切/复制/粘贴菜单时,下部文本块永远不会更新,因为 PreNotifyInput 永远不会触发。
XAML:
<Window x:Class="InputMgrDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<StackPanel>
<TextBox TextChanged="TextBox_TextChanged" />
<TextBlock Name="_text" />
</StackPanel>
</Window>
隐藏代码:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace InputMgrDemo
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
InputManager.Current.PreNotifyInput += ((sender, e) => _userInput = true);
InputManager.Current.PostNotifyInput += ((sender, args) => _userInput = false);
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (_userInput)
{
_text.Text = (sender as TextBox).Text;
}
}
private bool _userInput;
}
}
I'm using the InputManager to check if changes to controls are done by user or code. This works fine, except when user uses the context menu for cut/copy/paste. If the user do ctrl+v in a textbox, InputManager correctly notices it. However, if the paste is done from the context menu of the textbox, the InputManager never fires the PreNotifyInput or PostNotifyInput events. Anyone knows why? Or how to detect that these user actions? Below is a working sample. The lower textblock never gets updated when user uses the cut/copy/paste menu in the above textbox since PreNotifyInput never fires.
XAML:
<Window x:Class="InputMgrDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<StackPanel>
<TextBox TextChanged="TextBox_TextChanged" />
<TextBlock Name="_text" />
</StackPanel>
</Window>
Code behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace InputMgrDemo
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
InputManager.Current.PreNotifyInput += ((sender, e) => _userInput = true);
InputManager.Current.PostNotifyInput += ((sender, args) => _userInput = false);
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (_userInput)
{
_text.Text = (sender as TextBox).Text;
}
}
private bool _userInput;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
实际上,PreNotifyInput 事件确实在 MouseLeftButtonUp 事件上触发,但 PostNotifyInput 在实际粘贴发生之前触发。
以下是操作顺序:
由于处理了 MouseLeftButtonUp 事件,因此调用 PostNotifyInput 事件处理程序
由 Dispatcher 安排的任何渲染完成
Dispatcher 调用 MenuItem 中的回调
p>
在 WPF 中,“的效果用户输入”可以通过调度程序回调等任意延迟,因此您无法知道更改是否是由于用户输入引起的。
事实上,从理论上讲,这通常是正确的。考虑以下场景:
显然,在每种情况下,更改都是由用户输入引起的;-) 你明白我的意思了吗?从哲学上讲,没有根本的方法来确定更改是由您的用户还是其他人进行的。
如果您真正想要的是“用户在此应用程序中单击鼠标或使用键盘的时间与应用程序空闲的时间之间发生的任何更改”,您可以实现此功能:
但在这种情况下,如果您有数据传入从外部源动态输入的内容可能会被错误地视为用户输入。
另一种方法是将你的方法颠倒过来:每当你从外部数据源刷新数据时,设置一个标志来表明你正在这样做。然后,每当您看到未设置该标志的更改时,您都会认为这是用户交互。如果您可以确保所有外部数据更新都发生在 DispatcherPriority.Render 之上,那么这可能会更容易实现。
Actually the PreNotifyInput event does fire on the MouseLeftButtonUp event, but then the PostNotifyInput fires before the actual paste occurs.
Here is the sequence of operations:
Your PostNotifyInput event handler is called since the MouseLeftButtonUp event is handled
Any rendering scheduled by the Dispatcher completes
The Dispatcher invokes the callback in MenuItem
In WPF the effects of "user input" can be arbitrarily delayed by dispatcher callbacks, etc, so you cannot know whether a change is due to user input or not.
In fact, theoretically speaking this is generally true. Consider the following scenarios:
Clearly in each of these cases the change was caused by user input ;-) Do you see where I'm going with this? Philosophically there is no fundamental way to decide whether a change was made by your user or someone else.
If what you really want is "any changes that occur between the time the user clicks the mouse or uses the keyboard in this application and the time the application goes idle," you can implement this:
But in this case if you have data coming in dynamically from an external feed it may be erroneously considered to be user input.
Another approach is to flip yours upside down: Any time you refresh data from an external data source, set a flag saying you are doing so. Then any time you see changes with that flag not set, you assume it was user interaction. This may be easier to implement if you can ensure that all your external data updates happen above DispatcherPriority.Render.