Creating a new WPF window with a new thread error

void itemCommand_Click(Office.CommandBarButton Ctrl, ref bool CancelDefault) { var thread = new Thread(() => { if (LoginCheck()) { ItemWindow itw = new ItemWindow(); //Dispatcher.CurrentDispatcher.Invoke((System.Action)(() => //{ itw.Show(); itw.Closed += (sender2, e2) => { itw.Dispatcher.InvokeShutdown(); }; //})); Dispatcher.Run(); } }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); } 

I continue to receive the error message "The calling thread cannot access this object because another thread belongs to it." on line "itw.show ();" when this function is called twice. It works great for the first call, and after the window is closed and tries to open it again, it fails. When I commented on the Invoke method, it also does not work with the dispatcher. Please help me find a solution. Thanks.

----------------- Edit

The reason I am creating a new thread is because it is an Excel add-in. I cannot create windows from the main thread, which is an advantage that comes across windows if I create them from the main thread.
I do not understand why a new instance (ItemWindow) from a new thread collides with an old thread.

+8
multithreading c # wpf excel-addins
source share
3 answers

I created a simple test method in a new application that gets called when I click the button (only) in my main form. The method is as follows:

 private void Button_Click(object sender, RoutedEventArgs e) { Thread thread = new Thread(() => { Window1 window = new Window1(); window.Closed += (s, a) => window.Dispatcher.InvokeShutdown(); window.Show(); System.Windows.Threading.Dispatcher.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); } 

Window1 is the window class I made, and there is only one TextBlock . I can click this button as many times as I want, and it continues to open new windows without problems (regardless of whether I close the previous one).

I suspect the problem is in code that you are not showing somewhere. You must be very careful that nothing in your new thread tries to access any user interface associated with your main thread. Windows running on separate threads cannot communicate with each other unless they go through the manager of another thread. The exception you see is thrown when any method or property of DispatcherObject is accessed from a thread other than the one that created the object.

Going back, why is it important that the new window is in its stream? If the new window does not monopolize the stream, it will probably work perfectly in the main stream. If you perform some lengthy lock operation, it is possible that only this operation should be moved to the stream, and not to the entire window. I do not know what you are doing exactly, but you can think about it.


EDIT: realizing that you cannot work in a typical WPF application (it looks like you can be in the Office plugin), I updated my test to run fully autonomous windows in its threads. However, I can still run two windows in a row without problems.

Here is my new test. This method and the test class Window1 are the entirety of my application.

 [STAThread] public static int Main(string[] args) { ThreadStart threadFunc = () => { Window1 window = new Window1(); window.Closed += (s, a) => window.Dispatcher.InvokeShutdown(); window.Show(); System.Windows.Threading.Dispatcher.Run(); }; Thread thread = new Thread(threadFunc); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); thread = new Thread(threadFunc); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); return 0; } 

So, apparently, there is nothing inherently wrong with what you are trying to do, and I don't see an obvious problem in your code. I suspect that in your user window there is some incorrect connection between threads while it is being displayed. (Either this, or you have encountered a problem specific to Office plugins.)

0
source share

You are trying to connect an event handler to ItemWindow after it is already visible.

You need to switch the order:

 ItemWindow itw = new ItemWindow(); itw.Show(); itw.Closed += (sender2, e2) => { itw.Dispatcher.InvokeShutdown(); }; 

to

 ItemWindow itw = new ItemWindow(); itw.Closed += (sender2, e2) => { itw.Dispatcher.InvokeShutdown(); }; itw.Show(); 
0
source share

A possible cause is dependency properties. Property dependencies are a bit picky when it comes to streaming.

Even if you do not define your own DepProps, your window will still have some, and there is no way to get rid of them.

DepProps have a significant drawback: they are thread bound and cannot be accessed from another thread. Which thread contains all the rights is determined by the thread that initializes DepProps, in your case the first call to new ItemWindow() . After that, first call your thread and you will need this thread to access your DepProps.

This is not a problem for the first window, but the second obviously had a different thread. I donโ€™t know exactly how DepProps does it, but you can try to capture and restore the synchronization context of the first stream. Another option would be to capture the dispatcher of the first thread (rather than the main thread alone).

-one
source share

All Articles