I am starting a new UI-Thread in my WPF-application. Now I am searching a way to get a list with all windows in this thread - like I will get it for the main-thread with System.Windows.Application.Current.Windows.
Is there something in the .NET-Framework or does I have to implement it myself? When I have to implement it myself, perhaps someone have little bit of sample-code?
To quote MSDN:
A Window reference is automatically added to Windows as soon as a window is instantiated on the user interface (UI) thread; windows that are created by worker threads are not added. A Window reference is automatically removed after its Closing event has been handled and before its Closed event is raised.
By default, the first item added to the Windows property becomes the MainWindow.
This property is available only from the thread that created the Application object.
So it seems the windows created by worker threads are not hold in any collection automatically. I assume you create that window on the worker thread - so you should store a reference to it yourself for later access (you could do that in the Windows constructor by adding this to some window manager class)
Related
http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
Executes the specified delegate on the thread that owns the control's
underlying window handle.
According to the MSDN article, a thread can own other handles.
My best guess, is that the thread is some special super kernel object, with a handle that other handles can refer too?
like:
Handle | Thread-Handle-Reference
3201 | 20
4882 | 20
4827 | 7
In these terms, yes.
Basically, behind the scenes of the Windows GUI is a "message loop", which is a two-way communication between the Windows OS (which knows about the mouse, keyboard and other input hardware) and your program (which doesn't need to know the specifics, but does need to be responsive to user input within your app based on these input devices). There is a thread in your program (the main program execution thread, usually) that maintains this loop, listening for messages coming into the program from Windows, and parsing and passing messages to the various GUI controls and other code objects. This "GUI messaging thread" knows and maintains references to all the window handles of all GUI objects in your program; it must, because if it doesn't, it cannot pass messages to them and will not be listening for messages from them.
It is generally a bad idea to try to do something to a GUI control instance from outside the thread that is connected to the message loop. By doing so, it is possible for the control or sub-controls owned by the control to become detached from the message loop, or to never be attached in the first place. The "GUI message thread" then no longer knows about that control, and is no longer passing messages to or from it. Those controls become "rogue"; neither the program nor Windows can tell the control to move, redraw itself, or go away. The only thing Windows can do at that point to "control" the window is to shut down the process that owns it, thus terminating your entire program.
To avoid this, GUI controls have a special method "Invoke" (and an asynchronous cousin "BeginInvoke") designed to be used from outside the GUI messaging thread. These methods basically send a message from the window to itself through the Windows message loop that causes the main GUI thread to execute the delegate specified in the Invoke call. By doing so, any new GUI objects created within or as a result of that code will be known to the main GUI thread.
A custom thread can own handles when the handle is created in the custom thread. Actually i don't think that you can switch the owner of the handle. Sharing should be not possible too.
A thread can own multiple handles at once.
Every window is owned by the thread which created the window. Many window operations can only be performed on that thread, so it's important to have a mechanism to ensure that code is executed on the window's thread.
Forms.Invoke is one such mechanism.
When you create an empty WinForms application with Visual Studio, the template has the STAThread attribute in the main application class.
I have been reading some docs about it, but I'm not sure if I understood it at all.
Really I have some questions about it:
Why is this attribute added?
What does it mean?
What happens if you remove this attribute?
To quote from an MSDN blog,
When the STAThreadAttribute is applied, it changes the apartment state of the current thread to be single threaded. Without getting into a huge discussion about COM and threading, this attribute ensures the communication mechanism between the current thread and other threads that may want to talk to it via COM. When you're using Windows Forms, depending on the feature you're using, it may be using COM interop in order to communicate with operating system components. Good examples of this are the Clipboard and the File Dialogs.
1. Why is this attribute added?
Because it is required by the ActiveX object model. And you can drop ActiveX controls on a WinForm (so it is there for compatibility) OR some .NET classes use native controls which require that attribute.
2. What does it mean?
It means the thread runs in the single-threaded apartment model.
3. What happens if you remove this attribute?
If the attribute is removed, the behavior is undefined. The program may fail at random, with sometimes sensible error messages. For example, things may work now, then break with a service pack.
3.What happens if you remove this attribute?
I just add a simple example which demonstrates the problem.
I created simple WinForms app with a button and an OpenFileDialog. On button click I run a thread which shows the openFileDialog. I launch the app with and without STAThread and results of clicking the button are the same - it throws the exception "Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on".
It looks as if there is no difference. But no.
Then I changed showing the openFileDialog by calling the method below:
private void ShowOFD()
{
if (InvokeRequired)
{
BeginInvoke(new Action(ShowOFD));
return;
}
openFileDialog1.ShowDialog(this);
}
With STAThread it works fine as expected. Without STAThread it throws the exception:
"Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process".
Then I launch the app several times without debugger (detached from visual studio). One time the app just silently closed, another time the app closed with the message "vshost has stopped working"
It means that Windows Forms programs use a single-threaded apartment state. MTA and free threaded apartment states are not supported.
I have an app that runs a process which needs to open an internet explorer, go to an url, and do some stuff there, input some data, and return.
This usually takes a while (several pages that need to be filled, doesn't matter). The problem is, while this process is being done, the calling app (a standard wpf app) UI is unresponsive/frozen. When the process returns, i have some info that i need to set in one of the WPF app's objects
The main problem is that since IE needs to be called from within an STA thread, if I try to call it from within the dispatcher asynchronously or synchronously, for some reason the UI is blocked (i have tried with different DispatcherPriority-es but didn't get lucky).
If i start a new BackgroundWorker, that thread is in MTA mode (and i can't switch it back), so there's a problem and i have an exception
I'm really lost here, could anyone put some light into this? maybe what i want to do is simply not possible.
Have you tried creating your own background thread (not relying on BackgroundWorker), and set its ApartmentState to STA?
I have a taskBarIcon element extending Application Context from which my entire UI is designed. This is because the original functionality of the application was to run a background process and simply provide the icon as a confirmation that the app was running.
However, I am now adding additional functionality in the form of a menu that may be accessed by right clicking the icon, and since the core functionality is running on one thread, and the icon on the main thread, I am having issues accessing the icon in the simple case of needing to display a notification bubble. There are no other points at which the two threads may be accessing the same memory, so synchronization is not really an issue.
I am used to Java, in which this process is far simpler. I've read the articles I can find regarding the Invoke-Delegate dance that C# requires, but none are specific to an object extending Application Context. My current implementation is far too unpredictable to be production safe.
My question is this: How do I send the message to the other process to display the notification bubble, without disturbing the accessibility of the menu? Specifically, a simple example with a UI class extending Application Context and a class on a separate thread calling the invoke method would be very helpful.
I really appreciate any help!
badPanda
You could just as well use a SynchronizationContext object that you assign to SynchronizationContext.Current on the same thread that you create the notification bubble. You would then pass your SynchronizationContext object into whatever component the menu is on and it would use context.Send(....) to send a message. Or, if you have access to the notification bubble component or the form it's on, you could do form.Invoke((MethodInvoker)delegate {....});
When you create an empty WinForms application with Visual Studio, the template has the STAThread attribute in the main application class.
I have been reading some docs about it, but I'm not sure if I understood it at all.
Really I have some questions about it:
Why is this attribute added?
What does it mean?
What happens if you remove this attribute?
To quote from an MSDN blog,
When the STAThreadAttribute is applied, it changes the apartment state of the current thread to be single threaded. Without getting into a huge discussion about COM and threading, this attribute ensures the communication mechanism between the current thread and other threads that may want to talk to it via COM. When you're using Windows Forms, depending on the feature you're using, it may be using COM interop in order to communicate with operating system components. Good examples of this are the Clipboard and the File Dialogs.
1. Why is this attribute added?
Because it is required by the ActiveX object model. And you can drop ActiveX controls on a WinForm (so it is there for compatibility) OR some .NET classes use native controls which require that attribute.
2. What does it mean?
It means the thread runs in the single-threaded apartment model.
3. What happens if you remove this attribute?
If the attribute is removed, the behavior is undefined. The program may fail at random, with sometimes sensible error messages. For example, things may work now, then break with a service pack.
3.What happens if you remove this attribute?
I just add a simple example which demonstrates the problem.
I created simple WinForms app with a button and an OpenFileDialog. On button click I run a thread which shows the openFileDialog. I launch the app with and without STAThread and results of clicking the button are the same - it throws the exception "Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on".
It looks as if there is no difference. But no.
Then I changed showing the openFileDialog by calling the method below:
private void ShowOFD()
{
if (InvokeRequired)
{
BeginInvoke(new Action(ShowOFD));
return;
}
openFileDialog1.ShowDialog(this);
}
With STAThread it works fine as expected. Without STAThread it throws the exception:
"Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process".
Then I launch the app several times without debugger (detached from visual studio). One time the app just silently closed, another time the app closed with the message "vshost has stopped working"
It means that Windows Forms programs use a single-threaded apartment state. MTA and free threaded apartment states are not supported.