【问题标题】:Hide / Show Winforms GUI C# from another thread从另一个线程隐藏/显示 Winforms GUI C#
【发布时间】:2010-02-03 18:04:57
【问题描述】:

这篇文章是Way to quickly show/hide WinForms GUI C# 的延续,因为在这种特殊情况下它对我不起作用。

我有两个问题:

  • 1 是 mainAnnounceWindow gui 应该开始隐藏,然后在被以下调用时: windowStateChange("Show") 它应该显示,通过 windowStateChange("Hide") 它应该隐藏。它不能正确地做到这一点,因为当我启动应用程序时,它会在 0.5 秒内可见(我看到它在闪烁)。有没有办法让它开始隐藏而不闪烁半秒钟。

  • 2 是从 myThreadHandler (Queue.Work) 调用时 windowStateChange 不能正常工作。

    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();
    
    }
    }
    

另一个类:

  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
            }
        }
    }

}

问题在于:

                Program.windowStateChange("Show");
                Thread.Sleep(5000); // simulate work...
                Program.windowStateChange("Hide");

当我调用 Program.windowStateChange("Show");从其他线程内部,gui显示但不完全......就像我可以看到它想显示,但它没有。就像一个应用程序的挂起。但是当 Thread.Sleep(5000) 通过时,应用就隐藏了。

调用:

                Program.mainAnnounceWindow.setLogTextBox(task);
                Program.mainAnnounceWindow.setLogTrayTip(task);

没有问题。 BaloonTip 显示,只是 Gui 没有正确显示。我做错了什么。

哦,当然我做了一些剪切/粘贴,所以它可能会遗漏一些东西。如果有必要添加一些东西,请告诉我。

关于,

疯子

【问题讨论】:

    标签: c# .net winforms show-hide


    【解决方案1】:

    问题是你的主线程被锁定了,因为你添加了这个:

    while (true) { 
        Thread.Sleep(1000); 
    } 
    

    这将阻止窗口线程适当地接收和处理窗口消息(例如显示和隐藏)。

    您还需要使用mainAnnounceWindow.Show(),而不是mainAnnounceWindow.ShowDialog(),因为这会阻止控制正确返回到主线程。您应该在 Main 例程中调用 Application.Run(mainAnnounceWindow)

    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);
    }
    

    【讨论】:

    • myThreadGuiAnnounce.Start();正在启动线程 private static void showGuiAnnounce() { mainAnnounceWindow.ShowDialog();所以事实上 GUI 有它自己的线程独立于 Main。所以 Thra.Sleep(1000) 只是让主线程进入睡眠状态,而 gui 在另一个线程中时什么也不做?它不应该工作吗?
    • 这不安全。 STA 需要启动新线程,如果您使用 ShowDialog,窗口将不会处理消息并且能够以您想要的方式隐藏。将窗口留在主线程中,并正常显示(非对话框),您的代码很可能会按照您想要的方式工作......
    • 确实如此。如果我不使用单独的线程来创建 mainAnnounceWindow.. 并且我使用主线程作为 Gui 线程,那么您的解决方案就可以工作。但是,如果我想让主线程留作其他事情怎么办(因为 Thread.Sleep 在那里,所以主线程不会退出。
    • 将 GUI 留在主线程上,并将您的工作推到其他线程上几乎总是更好。这在现在和将来都将更易于维护。
    • 好的。您的解决方案工作正常,我想我可以忍受 GUI 在主线程中。我的第二个问题是什么,当启动时 gui 变得可见闪烁。我添加了: private void Announce_Shown(object sender, System.EventArgs e) { this.Hide(); } 让它在启动时隐藏.. 有什么更好的方法来做到这一点?
    【解决方案2】:

    您的问题是您正在从非 ui 线程访问 ui 对象,这是不允许的。您需要将包装您想要执行的操作的委托传递给其中一个 ui 控件(可能是您的表单对象)上的 Invoke 或 BeginInvoke 方法。

    【讨论】:

    • 我正在使用 public static void windowStateChange(string varState) 它使用 Invoke 进入 GUI 线程。还不够吗?
    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    相关资源
    最近更新 更多