Hide / Show Winforms GUI C# from another thread
This post is continuation of Way to quickly show/hide WinForms GUI C#, as it doesn't work for me in this particular case.
I've got 2 problems:
1 is that the mainAnnounceWindow gui should start hidden and later on when called by: windowStateChange("Show") it should show, by windowStateChange("Hide") it should hide. It doesn't do that properly as when i start app it's visible for like 0,5 s (i see it blinking). Is there a way to make it start hidden and not blink for half a second.
2 is that windowStateChange doesn't work properly when called from myThreadHandler (Queue.Work).
internal class Program { public delegate void StateCallBack(string varState); public static readonly Announce mainAnnounceWindow = new Announce(); public static readonly Thread myThreadGuiAnnounce = new Thread(showGuiAnnounce); public static readonly Thread myThreadTcpClient = new Thread(threadTcpClient); public static readonly Thread myThreadUdpMonitor = new Thread(threadUdpMonitor); public static readonly Thread myThreadHandler = new Thread(Queue.work); public static void Main() { myThreadGuiAnnounce.Start(); myThreadTcpClient.Start(); myThreadUdpMonitor.Start(); myThreadHandler.Start(); windowStateChange("Hide"); while (true) { Thread.Sleep(1000); } } public static void windowStateChange(string varState) { if (mainAnnounceWindow.InvokeRequired) { mainAnnounceWindow.Invoke(new StateCallBack(windowStateChange), new object[] {varState}); } else { if (varState == "Hide") { mainAnnounceWindow.Hide(); mainAnnounceWindow.TopMost = false; } else { mainAnnounceWindow.Show(); mainAnnounceWindow.TopMost = true; } } } private static void showGuiAnnounce() { mainAnnounceWindow.ShowDialog(); } }
Another class:
public class Queue : IDisposable {
public static void work() {
while (true) {
string task = null;
lock (locker)
if (tasks.Count > 0) {
task = tasks.Dequeue();
if (task == null) {
return;
}
}
if (task != null) {
//MessageBox.Show("Performing task: " + task);
Program.mainAnnounceWindow.setLogTextBox(task);
Program.mainAnnounceWindow.setLogTrayTip(task);
Program.windowStateChange("Show");
Thread.Sleep(5000); // simulate work...
Program.windowStateChange("Hide");
} else {
wh.WaitOne(); // No more tasks - wait for a signal
}
}
}
}
The problem is with:
Program.windowStateChange("Show");
Thread.Sleep(5000); // simulate work...
Program.windowStateChange("Hide");
When i call Program.windowStateChange("Show"); from inside other thread the gui shows but not quite.. like i can see that it would like to show, but it doesn't. Like a hang of app. But when the Thread.Sleep(5000) passes the app hides.
Calling:
Program.mainAnnounceWindow.setLogTextBox(task);
Program.mainAnnoun开发者_如何学编程ceWindow.setLogTrayTip(task);
Has no problem. BaloonTip shows, just the Gui doesn't show up properly. Something i'm doing wrong.
Oh and of course i did some cut/paste so it may miss some stuff. If it's necessary to add something let me know.
With regards,
MadBoy
The problem is that your main thread is locked up, because you added this:
while (true) {
Thread.Sleep(1000);
}
This will prevent the window thread from receiving and processing the windows messages (such as show and hide) appropriately.
You'll also want to use mainAnnounceWindow.Show()
, not mainAnnounceWindow.ShowDialog()
, as this will prevent control from returning properly to the main thread. You should just call Application.Run(mainAnnounceWindow)
in your Main routine:
public static void Main()
{
myThreadGuiAnnounce.Start();
myThreadTcpClient.Start();
myThreadUdpMonitor.Start();
myThreadHandler.Start();
// Just change your main window's load to hide itself... windowStateChange("Hide");
Application.Run(mainAnnounceWindow);
}
Your problem is you are accessing a ui object from a non ui thread, which is not allowed. You need to pass a delegate wrapping the operation you want to perform to the Invoke or BeginInvoke methods on one of the ui controls (perhaps your form object).
精彩评论