PnP
PnP

Reputation: 3185

C# WPF Dispatcher Timer Tick in Separate Thread

So I have a basic WPF application, that OnStartup creates a DispatcherTimer and has a tick method that runs a basic SQL query to check the status of some arbitrary table.

It is a variable query in terms of how long it takes to execute.

If I am in the main application window, when the background DispatcherTimer runs (DispatcherTimer code being within the App.xaml, not the MainWindow.xaml), the window hangs while the query runs, and as the query runs every 5 seconds, the GUI is unresponsive.

It seems a new thread is the way to go, but I am lost on where to begin. I am relatively new to C#/WPF so it's all a learning curve at the moment. How would I go about invoking my dispatcherTimer_Tickwithin a new thread, to avoid this problem?

DispatcherTimer dispatcherTimer;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        MainWindow = new MainWindow();
        MainWindow.Closing += MainWindow_Closing;

        _notifyIcon = new System.Windows.Forms.NotifyIcon();
        _notifyIcon.DoubleClick += (s, args) => ShowMainWindow();
        _notifyIcon.Icon = BackgroundApplication.Properties.Resources.GTL;
        _notifyIcon.Visible = true;

        CreateContextMenu();

        dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
        dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
        dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
        dispatcherTimer.Start();

    }

    private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        // Console.WriteLine("Tick");

        SqlConnection cnn;
        connectionString = @"SOME_DATA_SOURCE";
        cnn = new SqlConnection(connectionString);
        cnn.Open();
        // MessageBox.Show("Connection Open  !");
        // cnn.Close();

        SqlCommand command;
        SqlDataReader dataReader;
        String sql = "";
        Int16 output = 0;

        sql = "SOME SQL STATEMENT";
        command = new SqlCommand(sql, cnn);
        dataReader = command.ExecuteReader();

        while (dataReader.Read())
        {
            output = Int16.Parse(dataReader[""].ToString());
        }

        if(output > 0)
        {
            _notifyIcon.Icon = BackgroundApplication.Properties.Resources.RTL;  

        }

        _notifyIcon.Text = "Current Issues: " + output;

    }

Upvotes: 0

Views: 1845

Answers (1)

Clemens
Clemens

Reputation: 128061

Make the Tick handler async and await the long-running call:

private async void dispatcherTimer_Tick(object sender, EventArgs e)
{
    await Task.Run(() =>
    {
        // make query here
    });

    // update the UI outside the Task
    _notifyIcon.Text = "Current Issues: " + output;
}

Even better would be to directly call async methods, like

private async void dispatcherTimer_Tick(object sender, EventArgs e)
{
    ...
    dataReader = await command.ExecuteReaderAsync();
    ...
}

Upvotes: 4

Related Questions