0

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;

    }

1 Answer 1

4

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();
    ...
}
Sign up to request clarification or add additional context in comments.

4 Comments

Perfect, thank you! So is the await command.ExecuteReaderAsync(); essentially running the SQL query within another thread?
Not sure if it's a separate thread or not - and it doesn't actually matter. Many file I/O calls are inherently asynchronous and don't need a thread.
But a long running query here won't prevent the MainWindow.xaml from being responsive? i.e. it will prevent the hang?
Sure, just give it a try.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.