在WPF处理期间检测输入击键

时间:2011-01-25 16:04:38

标签: wpf input detect

问候,

我想编写在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,看看我是否可以在处理过程中刷新键盘信息,但我没有成功使用任何技术。

我没有想法。有人可以提出什么吗?提前感谢您的协助。

  • 大卫

2 个答案:

答案 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();
    }