1

I have a TabConrol that when a user does certain things, a new TabItem is programmatically added. In this tab there is a Frame that will contain the desired Page.XAML. This is all working perfectly like this;

private void addNewTab()
{
   TabItem tab = new TabItem();
   Grid g = new Grid();
   Frame f = newFrame();
   g.Children.Add(f);
   tab.Content = g;
   MyTabControl.Items.Add(tab);
   MyTabControl.SelectedItem = tab;
}

private Frame newFrame()
{
   Frame f = new Frame();
   //Full logic for Frame removed
   f.Navigate(new MyPage());
   return f;
}

Issues is sometimes the loading of the new Frame can take sometime. So I wanted to do this async. So while it loads there could be a loading animation. I figured that this would work;

private async void addNewTab()
{
   TabItem tab = new TabItem();
   Grid g = new Grid();

   var test = Task<Frame>.Factory.StartNew(() => newFrame(selectTab, value));
   await test;
   f = test.Result;

   g.Children.Add(f);
   tab.Content = g;
   MyTabControl.Items.Add(tab);
   MyTabControl.SelectedItem = tab;
}

private Frame newFrame()
{
   Frame f = new Frame();
   //Full logic for Frame removed
   f.Navigate(new MyPage());
   return f;
}

Problem is that it returns the follow error on Frame f = new Frame(); in newFrame() at run;

An exception of type 'System.InvalidOperationException' occurred in PresentationCore.dll but was not handled in user code

Additional information: The calling thread must be STA, because many UI components require this.

Starting to think I am trying to solve this the wrong way. What is the best way to handle this?

Xaphann
  • 3,195
  • 10
  • 42
  • 70
  • possible duplicate of [How to run something in the STA thread?](http://stackoverflow.com/questions/2378016/how-to-run-something-in-the-sta-thread) – Sebastian P. Jul 15 '15 at 21:15

1 Answers1

6

Building any reasonable UI is an extremely fast operation. However, determining the data to display in that UI can take any amount of time. So I assume that's what's actually slow.

You can't build the actual UI components on a background thread; that's what the exception tells you.

But you can build the data on the background thread and then later load it into the UI:

private async Task addNewTabAsync()
{
  TabItem tab = new TabItem();
  Grid g = new Grid();

  var data = await Task.Run(() => getData(value));
  Frame f = new Frame();
  // Fill out frame with data.
  f.Navigate(new MyPage());

  g.Children.Add(f);
  tab.Content = g;
  MyTabControl.Items.Add(tab);
  MyTabControl.SelectedItem = tab;
}

Note that I changed async void to async Task (and added the Async suffix), and changed StartNew to Run to follow best practices.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810