Julian Gold
Julian Gold

Reputation: 1286

WPF: polling the keyboard

I am working on a WPF application that runs on an embedded device (.NET Standard 4 for embedded). It has a whole bunch of hardware attached which gets in the way when I'm testing, so I created a DummyHardware interface that just does nothing except print log messages when I run my unit tests, or run stand-alone on my development PC.

So far so good. But: the device has a 4-key keypad which is polled. My dummy keypad class went into an infinite loop when waiting for a key to be pressed, because there were no keys to press :-) So I thought, "Ok, I'll poll the keyboard to see if 1,2,3 or 4 is pressed". But I get the exception

The calling thread must be STA...

when I called Keyboard.IsKeyDown( Key.D1 ). The keypad polling takes place in a separate thread (to decouple from the generally slow serial comms of the rest of the hardware). Any thoughts on how to proceed? Invoke?

Note: one alternative would be to just skip the "wait for key" test on dummy hardware, but then I don't know which key was pressed and the following code which relies on it won't function correctly. Yuk.

Upvotes: 1

Views: 1304

Answers (2)

Sheridan
Sheridan

Reputation: 69979

I have a simple method that handles running on the UI thread for me:

public object RunOnUiThread(Delegate method)
{
    return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}

Where Dispatcher is initialised using Dispatcher.CurrentDispatcher from the UI thread. It can be called from any thread and is used like this:

UiThreadManager.RunOnUiThread((Action)delegate
{
    // running on the UI thread
});

Upvotes: 1

Andy
Andy

Reputation: 6466

You can just set the ApartmentState to be STA. using the Thread.SetApartmentState method

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace staThread
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Thread keyboardThread;

        public MainWindow()
        {
            InitializeComponent();
            keyboardThread = new Thread(new ThreadStart(KeyboardThread));
            keyboardThread.SetApartmentState(ApartmentState.STA);
            keyboardThread.Start();
        }

        void KeyboardThread()
        {
            while (true)
            {
                if (Keyboard.IsKeyDown(Key.A))
                {
                }

                Thread.Sleep(100);
            }
        }
    }
}

Upvotes: 4

Related Questions