2011-01-25 78 views
0

問候檢測輸入按鍵,在WPF處理

我想寫一個事件處理程序中執行,一個WPF Windows應用程序中的代碼,可以檢測處理內部的按鍵,具體的「逍遙遊」字按鍵,循環。這將允許用戶逃避處理。我意識到這可能是用某種多線程方法完成的,但問題似乎很簡單,我想知道是否可以按如下方式完成:

//嘗試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; 
    }  

但不幸的是,我沒有看到鍵盤狀態的任何變化,因爲它執行。我也對調度員進行了一些調用,以瞭解在處理過程中是否可以獲取鍵盤信息,但我還沒有成功使用任何技術。

我出來的想法。有人能提出一些建議嗎預先感謝您的幫助。

  • 大衛

回答

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

重要的一點是,該不工作的方法是在一個單獨的線程,以便主線程可以處理用戶輸入執行(擊鍵)。

+0

我覺得上述兩個答案都很有幫助。我只需要接受多線程方法是實現這一目標的唯一方法。也許是因爲我自己在猶豫不決之後出現了多線程的複雜問題,我希望能夠實現在UI線程中無需將控制權返回給Windows的情況下檢查鍵盤狀態的方法。 我們在檢查過的示例之後對我們的解決方案進行建模。如果我們有任何更重要的併發症,我會發布。感謝你們的大力協助。 – 2011-01-25 20:56:20

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