Detecting input keystroke during WPF processing

青春壹個敷衍的年華 提交于 2019-12-10 12:23:48

问题


Greetings,

I want to write code that executes within an event handler, inside a WPF Windows application, that can detect a keypress, specifically an "Escape" character keypress, within a processing loop. This will allow the user to escape from processing. I realize this may be accomplished with some kind of multi-threaded approach, but the problem seems so simple I wondered if it might be accomplished as follows:

// Attempt 1: See if Keyboard static IsKeyDown method detects key presses while executing.
// Note that this was not successful. The Keyboard states do not appear to be updated during processing.

        bool iskeypressed = false;
        while (!iskeypressed)
        {
            System.Threading.Thread.Sleep(1000);
            if (Keyboard.IsKeyDown(Key.Enter))
                iskeypressed = true;  
        }

So, on to attempt #2. I saw some articles and samples using the Pinvoke "GetKeyboardState" method. I'm not sure I used the method correctly, but here is my attempt. It is a bit clumsy to refer to a Windows.Forms enumeration in a WPF application, but it seems like it could work.

// Attempt 2: Use Pinvoke GetKeyboardState method.
// So far, I've been unsuccessful with this as well, but I'm not sure my usage is correct.

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

But unfortunately, I'm not seeing any change in the keyboard states as this executes. I also played around a little with calls to the Dispatcher to see if I could get the keyboard information to refresh during processing, but I have not been successful with any technique.

I'm out of ideas. Can someone propose something? Thank you in advance for your assistance.

  • David

回答1:


Something like this:

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

The important point is that the method that does the work is executed in a separate thread so the main thread can process user input (key strokes).




回答2:


You can not detect a key event while you are blocking WPF by executing a very long loop. You must use a multithreaded approach or you have to split the loop.

Using a BackgroundWorker is an easy way to let WPF continue handling the frontend while executing the loop.

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


来源:https://stackoverflow.com/questions/4795786/detecting-input-keystroke-during-wpf-processing

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!