2010-02-03 2 views
0

Этот пост является продолжением Way to quickly show/hide WinForms GUI C#, так как он не работает для меня в данном конкретном случае.Скрыть/Показать Winforms GUI C# из другого потока

У меня есть 2 проблемы:

  • 1 является то, что mainAnnounceWindow графический интерфейс должен начать скрытый и позже, когда вызывается: windowStateChange («Показать») он должен показать, на windowStateChange («Скрыть») он должен скрыться. Это не так, как при запуске приложения, это видно за 0,5 с (я вижу, что он мигает). Есть ли способ заставить его начать скрываться и не мигать полсекунды.

  • 2 что windowStateChange не работает должным образом при вызове 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(); 
    
    } 
    } 
    

Другой класс:

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 ("Показать"); изнутри другой нити показывает gui, но не совсем. Как я вижу, что он хотел бы показать, но это не так. Как повесить приложение. Но когда Thread.Sleep (5000) пропускает скрытие приложения.

Призвание:

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

не имеет никаких проблем. BaloonTip показывает, что Gui не отображается правильно. Что-то я делаю неправильно.

О, и, конечно, я сделал некоторые вырезать/вставить, чтобы он мог пропустить некоторые вещи. Если нужно добавить что-то, дайте мне знать.

С уважением,

MadBoy

ответ

1

Проблема заключается в том, что ваш основной поток заблокирован, потому что вы добавили это:

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

Это предотвратит оконную нить от приема и обработки сообщений окна (например, показывать и скрывать) соответственно.

Вы также захотите использовать mainAnnounceWindow.Show(), а не mainAnnounceWindow.ShowDialog(), так как это предотвратит правильное возвращение элемента управления в основной поток. Вы должны просто позвонить 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); 
} 
+0

myThreadGuiAnnounce.Start(); запускает поток private static void showGuiAnnounce() {mainAnnounceWindow.ShowDialog(); }, так что на самом деле GUI имеет свою собственную ветку отдельно от Main. Итак, Threa.Sleep (1000) просто заставляет Main thread спать и ничего не делать, пока gui находится в другом потоке? Разве это не работает? – MadBoy

+0

Это не будет безопасно. Новый поток должен быть запущен STA, и если вы используете ShowDialog, окно не будет обрабатывать сообщения и быть в состоянии скрыть то, что вы хотите. Оставьте окно в главном потоке и покажите его нормально (без диалога), и ваш код, скорее всего, сработает wya, который вы хотите ... –

+0

Действительно. Если я не использую отдельный поток для создания mainAnnounceWindow .. и я использую Main thread как поток Gui, ваше решение работает. Но что, если бы я хотел бы, чтобы Main thread остался для других вещей (поскольку Thread.Sleep был там, поэтому Main thread не выходил. – MadBoy

1

Вашей проблемой вы обращаетесь к объекту щий из не Ui нити, которая не допускается. Вам нужно передать делегат, который завершает операцию, которую вы хотите выполнить, на методы Invoke или BeginInvoke на одном из элементов управления ui (возможно, ваш объект формы).

+0

Я использую государственную статическую силу windowStateChange (строку varState), которая использует Invoke, чтобы попасть в ГПИ-поток. разве это недостаточно? – MadBoy