【问题标题】:Detecting input keystroke during WPF processing在 WPF 处理期间检测输入击键
【发布时间】:2014-08-26 14:56:28
【问题描述】:

你好,

我想编写在 WPF Windows 应用程序内的事件处理程序中执行的代码,该代码可以检测处理循环中的按键,特别是“转义”字符按键。这将允许用户逃避处理。我意识到这可以通过某种多线程方法来完成,但问题似乎很简单,我想知道它是否可以如下完成:

// 尝试 1:查看 Keyboard 静态 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 以查看是否可以在处理过程中刷新键盘信息,但我没有成功使用任何技术。

我没有想法。有人可以提出一些建议吗?预先感谢您的协助。

  • 大卫

【问题讨论】:

    标签: wpf input detect


    【解决方案1】:

    类似这样的:

    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);
       }
    }
    

    重要的是,完成工作的方法在单独的线程中执行,因此主线程可以处理用户输入(击键)。

    【讨论】:

    • 我认为以上两个答案都非常有帮助。我只需要接受多线程方法是实现此目的的唯一方法。也许是因为我自己对多线程带来的复杂性犹豫不决,我曾希望实现一种方法来检查键盘状态,而无需在 UI 线程中将控制权返回给 Windows。我们在检查示例之后对我们的解决方案进行建模。如果我们有任何更严重的并发症,我会发布。感谢大家的大力协助。
    【解决方案2】:

    当您通过执行非常长的循环来阻止 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();
        }
    

    【讨论】:

      猜你喜欢
      • 2015-04-26
      • 1970-01-01
      • 2012-01-10
      • 2015-11-29
      • 1970-01-01
      • 1970-01-01
      • 2014-04-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多