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 {....});
Related
Using Winforms,
If I'm on a thread that is not the "main" ui thread can I safetly
Create a Form,
Call ShowDialog on that form
It seems like I would be obeying the rule of:
Winforms controls must be modified on the thread they were created in.
From some of the reading I've done it seems like ShowDialog will create its own message pump so that I don't need to worry about the Form being created on a thread that already has a message pump.
The background of the question is that I get a callback where I'd like to display some Winforms UI, but I don't have access to any other UI that I could use to Invoke to the main thread.
That's roughly correct, albeit that it is pretty important that you call the thread's SetApartmentState() method to switch the thread to STA. Important for many UI operations, including the clipboard, drag and drop and the shell dialogs. And that you usually have a crummy Z-order problem when the form that you create on the thread is not in the foreground and hides behind another window. Or has the nasty habit of actually do move in the foreground when the user doesn't expect it and grab a mouse click or keystroke unexpectedly.
These are hard problems to fix, they do make your app flaky. There's no good reason to not have a reference to invoke to, you can also pass it to the class some way some how. You've always got Application.OpenForms[0] to fall back on, if really necessary.
Yes, you can do that, but if you want the dialog to actually act like a modal dialog (i.e., block the parent Window, which I assume you want since you are calling ShowDialog) then be prepared to be disappointed.
What problem are you actually trying to solve here. It sounds like you want a modal dialog that doesn't block, which is a bit strange. If you explain the problem at hand there may exist a solution you have not yet considered.
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.
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?
My program consists of a large graphing UI control that I need to spend about 15 seconds re-loading every once in a while. Because the updating code works primarily with the UI control (maybe 90% of it actually sets properties on the control), it would make sense to me to actually let the UI thread handle that. I really don't want the control to visually re-paint while it is loading in a separate thread from the UI.
I also want a progress bar to update as well that lives in the status bar of the same application window. Is there a way to break the rule in this case and re-paint only the progress bar, or should I just open a new application window for the progress bar to live in?
What would you do in this particular case?
If you can break your primary task (ie. updating the graph) in many steps, you can perform each step as a separate dispatcher message. This will allow other messages to be processed, including giving you the ability to update progress information.
The basic pattern is:
Invoke your primary task, passing in zero for the step.
Perform the step.
If there are more steps, queue another message, passing in step + 1.
You can then add in progress updates at the appropriate points in your code.
PS. Not saying this is your best option - hard to tell without knowing all the details. But this is an option.
It is not really true that there is only one UI thread in an application, it is just that most windows applications only ever create UI objects in one thread so this thread becomes "the" UI thread in the application. It is easy to understand why - this makes the code simpler to understand, and protects us from implicit thread binding issues between controls.
This suggests a possible idea, should it prove impossible to improve the speed of updating the control (which is what I would suggest to do first). Create the UI control on a separate thread. You need to make sure that the thread is suitable for UI, that is to say the threading model is STA, and that it will pump messages and not die before the control is destroyed. I don't know if you need to create the parent window in the UI thread as well, or just the control but it may be worth experimenting here.
Find a graphing UI control that is more efficient. Unless the UI thread yields to the message loop any other updates won't happen (and it will slow down your graph control's updates).
I would suggest using a progressbar in a new window (without the form headers). Make it paint the progress bar by reading the shared properties of a graph control. this way you can avoid the thread blocking (sluggish loading).. And it gives you good visual experience (progressive painting on both the controls).
I'm looking at creating a tabbed interface which has user controls (possibly written by plug-in developers) within a tabbed or MDI interface. These plug-in controls could unintentionally freeze their GUI thread, and I'd prefer that they not influence user controls in other tabs. Much like Google Chrome creates a process for each tab; but in this case, just threads.
Or perhaps even an MDI interface where the child MDI forms are owned by separate threads?
I've found that while I can run multiple GUI threads at once, the Form level is where they MUST be separated. Any workarounds/ideas?
For those saying this shouldn't be needed, I call bullshit. Google's Chrome browser runs tabs in separate processes for security and UI reasons. I'm merely trying to duplicate this behavior. When the people writing the user controls are sucky plug-in developers, this is important.
No it is not possible to do this in the way you are describing. A control which is owned / affinitized to another GUI thread cannot be directly contained within a control which is owned / affinitized to a different thread in such a way that it's paint function runs on the other thread.
The right way to fix this situation is to write UserControls that don't perform long-running tasks on the UI thread. If the control is blocking and waiting on some computational task, fix that. Make that task run in the background, and have the control display some non-compute-intensive content until it's done. If that task freezes, the control will be frozen in its "I'm waiting..." state, but it won't intrude on the rest of the UI.
If you're using a third-party control that you can't fix, well, in the immortal words of Jay-Z, I feel bad for you, son.
For the most part, controls shouldn't be performing any processing. Their purpose is to provide interactivity between the user and the application. For example, it is not the job of a button to fetch data from a database and present it to the user. That being said, hopefully you are doing your processing in a controls event handler, such as the Click event on the Button control. In your event handler, you can prevent the UI from appearing "hung" by processing tasks in a background thread. The BackgroundWorker is often useful in these situations.
I suggest reading up on Threading. The Microsoft® .NET Framework Application Development Foundation book has a section on threading (even if no other certification books are read, I at least recommend all .NET developers read this book). Just remember not to update the UI from a child thread. Read an example on how to make a thread-safe call to Windows controls if you're not familiar with this approach.
Instead of having or owning different GUI threads, you should view the whole issue from a different angle. Why would you want a thread associated to tab's child control to be freezed? If it does freeze and everything else feezes too, threading aside, that's not done right from ground up.
What JaredPar pointed out is correct, but that doesn't mean you cannot achieve what you want. I assume you want stuff running within a tab to continue running/stopping without affecting other controls and user-experience.
I've done it before in a complex WinForm app. Here are some readings which might give you more insights:
Threading out tasks in a C#.NET GUI
Thread and GUI
Updating GUI from Other Threads in C#
Advanced Techniques To Avoid And Detect Deadlocks In .NET Apps