问候,
我想编写在WPF Windows应用程序内的事件处理程序中执行的代码,该代码可以在处理循环中检测按键,特别是“Escape”字符按键。这将允许用户逃避处理。我意识到这可以通过某种多线程方法来实现,但问题似乎很简单,我想知道它是否可以完成如下:
//尝试1:查看键盘静态IsKeyDown方法是否在执行时检测到按键 //请注意,这不成功。键盘状态似乎在处理期间不会更新。
bool iskeypressed = false;
while (!iskeypressed)
{
System.Threading.Thread.Sleep(1000);
if (Keyboard.IsKeyDown(Key.Enter))
iskeypressed = true;
}
所以,尝试#2。我使用Pinvoke“GetKeyboardState”方法看到了一些文章和示例。我不确定我是否正确使用了这种方法,但这是我的尝试。在WPF应用程序中引用Windows.Forms枚举有点笨拙,但似乎它可以工作。
//尝试2:使用Pinvoke GetKeyboardState方法 //到目前为止,我也没有成功,但我不确定我的用法是否正确。
bool iskeypressed = false;
while (!iskeypressed)
{
System.Threading.Thread.Sleep(1000);
if (isEscapePressed())
iskeypressed = true;
}
}
[DllImport("user32.dll")] public static extern int GetKeyboardState(byte[] lpKeyState);
private bool isEscapePressed()
{
byte[] keyboardState = new byte[255];
int keystate = GetKeyboardState(keyboardState);
if (keyboardState[(int)System.Windows.Forms.Keys.Escape] == 128)
return true;
else
return false;
}
但不幸的是,我没有看到键盘状态发生任何变化。我还打电话给Dispatcher,看看我是否可以在处理过程中刷新键盘信息,但我没有成功使用任何技术。
我没有想法。有人可以提出什么吗?提前感谢您的协助。
答案 0 :(得分:3)
这样的事情:
private bool IsCancelled { get; set; }
private void OnButtonClick(object sender, EventArgs e)
{
Action doWorkDelegate = DoWork;
doWorkDelegate.BeginInvoke(null, null);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.Key == Key.Escape) {
IsCancelled = true;
e.Handled = true;
} else {
base.OnKeyDown(e);
}
}
private void DoWork()
{
IsCancelled = false;
while (!IsCancelled)
{
System.Threading.Thread.Sleep(1000);
}
}
重要的是,执行工作的方法是在一个单独的线程中执行的,因此主线程可以处理用户输入(击键)。
答案 1 :(得分:1)
在通过执行非常长的循环阻止WPF时,无法检测到键事件。您必须使用多线程方法,或者必须拆分循环。
使用BackgroundWorker是让WPF在执行循环时继续处理前端的简单方法。
private BackgroundWorker bw;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (bw != null)
return;
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.WorkerReportsProgress = true;
bw.DoWork += (senderBw, eBw) =>
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(1000);
bw.ReportProgress(i);
if (eBw.Cancel)
return;
}
};
bw.ProgressChanged += (senderBw, eBw) =>
{
//TODO set progressbar to eBw.ProgressPercentage
};
bw.RunWorkerCompleted += (senderBw, eBw) =>
{
this.bw = null;
//TODO frontend stuff (hide progressbar etc)
};
bw.RunWorkerAsync();
}
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (this.bw != null && this.bw.IsBusy && e.Key == Key.Escape)
this.bw.CancelAsync();
}