-1

I've already found several topics about multithreading in wpf and got most things to work with dispatch, but there is one thing I havent figured out yet. I have a stackpanel called "stackpanel1" to which Im adding stackpanels (in another thread) called "stackrow" as children. (foreach-loop)

stackPanel1.Dispatcher.Invoke(new Action(() => stackPanel1.Children.Add(stackrow)));

its similar to this question: WPF C# - Editing a listbox from another thread

except my "new item" is an UI Element(stackrow) and I get the following error: InvalidOperationException was unhandled. The calling thread cannot access this object because a different thread owns it.

How do I dispatch "stackrow" in this line?

edit: stackrow is created in the foreachloop

mainthread (creates new thread) Thread t = new Thread(()=> addstackrows()); t.SetApartmentState(ApartmentState.STA); t.Start();

method addstackrows()

private void addstackrows()
{

  Dispatcher stackpaneldispatcher = stackPanel1.Dispatcher;                 
  stackPanel1.Dispatcher.Invoke(new Action(() => 
  stackPanel1.Children.Clear()));
  stackPanel1.Dispatcher.Invoke(new Action(() => 
  stackPanel1.Orientation = Orientation.Vertical));

  foreach (var randomelement in elementcollection)
  {
      StackPanel stackrow = new StackPanel();
      Dispatcher stackrowdp = stackrow.Dispatcher;

      stackrow.Dispatcher.Invoke(new Action(() => 
      stackrow.Orientation = Orientation.Horizontal));
      stackPanel1.Dispatcher.Invoke(new Action(() =>   
      stackPanel1.Children.Add(stackrow)));

  }

}
Community
  • 1
  • 1
  • Where is `stackrow` created? – ChrisF May 31 '13 at 21:09
  • 1 You can't manipulate UI elements from a background thread. 2 - You should NOT even be manipulating UI elements in procedural code in WPF. That is a crappy practice originated in some dinosaur technologies' incapabilities work properly with data binding. Post a screenshot of what you need and I can tell you the proper way to implement it in WPF. – Federico Berasategui May 31 '13 at 21:18
  • @ChrisF stackrow is created in the new thread. – morrismoss May 31 '13 at 21:34
  • 1
    @morrismoss you're doing it all wrong. You should be using an `ObservableCollection` and creating Data items, not UI elements, in a background thread. – Federico Berasategui May 31 '13 at 21:35
  • @HighCore Im a total newb to wpf and Im not familiar with the dos and don'ts. So Data Binding is the right way? my program gets several int-arrays(count = 6). My plan was to display them as Button.Contents. 6 Buttons per stackrow and for each array I add a stackrow to the stackpanel. I chose to use buttons because every int-element should (by users choice) trigger a method. – morrismoss May 31 '13 at 21:41
  • @morrismoss data binding is not the right way, it's the ONLY way in WPF (exaggerated). Yes, WPF requires a very different approach, take a look at Rachel's [excellent explanation](http://stackoverflow.com/a/15684569/643085) – Federico Berasategui May 31 '13 at 21:43
  • @HighCore Great, thank you for your answer and the link! I guess there is much to learn for me. – morrismoss May 31 '13 at 22:02

1 Answers1

0

You should create all your UI objects in the same thread:

private void addstackrows()
{

    Dispatcher stackpaneldispatcher = stackPanel1.Dispatcher;
    stackPanel1.Dispatcher.Invoke(new Action(() =>
    {
        stackPanel1.Children.Clear();
        stackPanel1.Orientation = Orientation.Vertical;
    }));

    foreach (var randomelement in elementcollection)
    {
        stackPanel1.Dispatcher.Invoke(new Action(() =>
        {
            StackPanel stackrow = new StackPanel();
            stackrow.Orientation = Orientation.Horizontal;
            stackPanel1.Children.Add(stackrow);
        }));
    }
}

Also, I would group all your Dispatcher calls. Each time you call Invoke there is a performance overhead. So, unless you do a time consuming operation inside your loop, it would be probably better to put the whole function inside a Invoke.

fcuesta
  • 4,429
  • 1
  • 18
  • 13