I have to buil a rather complex WPF UI (a hughe Grid) in code (no xaml invloved). Is there a way to stop the main UI thread from blocking while beeing in the process of building the Grid? Are there some portions of building the UI that can be outsourced to a workerthread? What parts of UI creation actually have to be on the UI thread?
What other options do I have to increase performance while building the UI? Is suspending the dispatcher or calling FrameworkElement.BeginInit a good idea?
If you can break the construction of your UI up into steps, you can do each of these steps as a separate message. This will allow other messages to be processed in between. Something like:
private delegate void BuildHandler();
private void BuildGridPart1()
{
//build first part of grid
Dispatcher.BeginInvoke(new BuildHandler(BuildGridPart2), DispatcherPriority.Background);
}
private void BuildGridPart2()
{
//build second part of grid
Dispatcher.BeginInvoke(new BuildHandler(BuildGridPart3), DispatcherPriority.Background);
}
//etc
You can refactor this to be cleaner (eg. one method with a state machine that tells you where in the grid you are up to), and automatically queue the next message at a lower priority so that input is always processed first. Bingo, you will have a responsive UI whilst building UI on the UI thread.
My feeling is that you might not have many options other than running on the UI thread.
If it were a case that the long time involved was due to gathering and arranging the data then a background thread would be the best option, and then call any UI dependency properties using the Dispatcher object. I'm assuming the time is not to gather any data it is purely down to programmatic creation of the UIElements.
As I understand it UI elements derive from DispatcherObject that gets the Dispatcher from the current working thread so that rules out creation of controls on another thread.
Then all Dependency Properties call Dispatcher.VerifyAccess when written to, that will raise an exception if accessed on the wrong thread. So that rules out updating databinding and properties on a different thread.
My first reaction would be like @Kent wrote.
To elaborate slightly, if you have a foreach loop for each row with another foreach for each column then you could, even though you are in the correct UI Thread, call Dispatcher.BeginInvoke to "yield" momentarily from your long running method. i.e to break it up and then pass control back to the UI thread to later carry on adding to the grid. The layout effort might be significantly greater and the overall time would be longer but a bit more responsive.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CreateRow(1);
}
private void CreateRow(int i)
{
//
// Construct row i of the grid
//
Dispatcher.BeginInvoke(DispatcherPriority.Background, new EventHandler(delegate { CreateRow(i + 1); }));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With