serious_tim
serious_tim

Reputation: 99

Multithreaded, Multi-Dispatcher WPF app still draws in a single thread?

I have a WPF & C# app that contains a large DataGrid, about 35 cols x 50 rows, to monitor a bunch of frequently changing values. The trouble is, when the whole grid is visible, refreshing it hangs up the user interface for almost a second. I refresh it explicitly every two seconds, which is fine for what I'm doing, but having the rest of the UI hang up is a real pain.

OK, so I decide I'll run the rest of the UI in a separate window in a separate thread with a separate Dispatcher. I wrote a toy window containing just a textBlock with an incrementing count that updates 10 times a second using a DispatcherTimer. However, rather than the count incrementing smoothly, it pauses while the grid refreshes, then resumes displaying with the count about 10 higher than it was when it paused, so timer events are getting handled. I'm just not seeing a refresh.

Does WPF only draw all its elements in a single thread? Any way around it?

Here's my 2nd window creation code:

private void Window_Loaded( object sender, RoutedEventArgs e )
{
    ThreadStart ts = new ThreadStart( RunSpareThread );
    m_spare_thread = new Thread( ts );
    m_spare_thread.IsBackground = true;
    m_spare_thread.Priority = ThreadPriority.Highest;
    m_spare_thread.SetApartmentState( ApartmentState.STA );
    m_spare_thread.Start();

    Dispatcher.Thread.Priority = ThreadPriority.Lowest;
}

void RunSpareThread()
{
    m_spare_window = new SpareWindow();
    m_spare_window.Show();
    Dispatcher.Run();
}

FYI I've tried implementing the grid a few different ways - as a ListView, as a Canvas that overrides OnRender and draws a whole bunch of GlyphRunDrawings - WPF is just incredibly slow at drawing this stuff.

Upvotes: 1

Views: 1337

Answers (2)

Andrew Hanlon
Andrew Hanlon

Reputation: 7421

Unfortunately yes. That said there are a number of things you can do to increase the responsiveness of your ui. One of the main things is to make sure that the least amount of work is being done in the UI thread. This means doing all of the DB reading etc. within a separate context. You should also look into how your grid is displaying your values - is it virtualizing? Then there is also how you are databinding, a bindingsource should allow you to only update the binding after all of the changes are finished.

Upvotes: 3

Sergii Vashchyshchuk
Sergii Vashchyshchuk

Reputation: 970

WPF is very fast if you use it properly.

Some tips:

  1. Implement model (or ViewModel in terms of MVVM) of the data you want to display. Be sure that it implements INotifyPropertyChanged interface. Bind collection of such models to your DataGrid;
  2. Do not refresh all data each N seconds. You should somehow detect data changes (using working thread) and update appropriate properties on appropriate models. Because of data binding, all changes will be automatically reflected on the DataGrid. So, you don't even need to use Dispatcher (at least explicitly);
  3. Use ListView instead of DataGrid if you don't need to do special actions with data (like editing, sorting, filtering, etc.);
  4. Consider implementation of a virtualization if you need to display a huge amount of rows.

Upvotes: 2

Related Questions