2014-11-14 57 views
0

這是我的代碼被執行:多線程 - 窗口先關閉,然後創建,即使在代碼創建的方法被稱爲第一

OpenMyWindowInNewThread(1280, 1024, 5); 
//do some stuff 
CloseMyWindow(); 

這裏是方法:

public void OpenMyWindowInNewThread(int width, int height, int top) 
    { 
     thread = new Thread(x => OpenMyWindow(width, height, top)); 
     thread.IsBackground = true; 
     thread.SetApartmentState(ApartmentState.STA); 
     thread.Start(); 
    } 

    public void CloseMyWindow() 
    { 
     if (myWindow != null) 
     { 
      myWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => 
      { 
       myWindow.Close(); 
       myWindow = null; 
      })); 
     } 
    } 

private void OpenMyWindow(int width, int height, int top) 
    { 
     myWindow = new MyView(); 
     myWindow.Closed += new EventHandler(MyWindow_Closed); 

     myWindow.Width = width; 
     myWindow.Height = height; 
     myWindow.Top = top; 
     myWindow.Left = 0; 

     myWindow.ShowDialog(); 
    } 

當我第一次調用第一個代碼時,屏幕顯示並關閉,因爲它應該。但是,當我第二次執行代碼時,會發生以下情況:首先調用OpenMyWindowInNewThread(),然後調用OpenMyWindow(),然後調用CloseMyWindow()方法中的if條件,之後調用MyView() OpenMyWindow()方法中的構造函數。所以,窗口永遠不會關閉,因爲它首先關閉,而不是創建。

這是怎麼發生的?有人可以解釋嗎?

+1

您正在使用單獨的線程來創建新窗口。該線程被設置爲後臺優先級。無法保證在關閉通話前它會執行。這是一個典型的競賽條件。在關閉窗口中使用manualresetevent和block,直到觸發爲止 – thorkia 2014-11-14 16:26:35

+2

不要創建多個UI線程。不要。爲整個應用程序使用單個UI線程。你只是將自己置身於一個試圖處理多個消息循環的傷害世界。 – Servy 2014-11-14 16:27:23

+0

你的描述實際上沒有意義。在構造函數返回之前,不能將myWindow設置爲新的表單引用。所以'CloseMyWindow()'在構造函數之前不能看到它非空。也就是說,正如其他人已經注意到的那樣,你確實在這裏有一場比賽,是的你應該在一個線程上完成所有的UI。如果您希望在進行其他一些處理時顯示對話框,請在UI線程中顯示對話框,然後使用「BackgroundWorker」或其他輔助線程執行其他處理(這可能不應在主UI上完成線程無論如何!) – 2014-11-14 21:53:12

回答

0

問題是你有兩個線程訪問窗口;在執行打開的線程完成其操作之前,關閉窗口的線程正在運行close方法。解決這個問題的最簡單方法是鎖定窗口的打開和關閉。如前所述,多個UI線程不是一個簡單的概念,它可能會非常非常混亂!

private static object _syncLock = new object(); 

public void CloseMyWindow() 
{ 
    lock(_syncLock) 
    { 
     if (myWindow != null) 
     { 
      myWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => 
      { 
       myWindow.Close(); 
       myWindow = null; 
      })); 
     } 
    } 
} 

private void OpenMyWindow(int width, int height, int top) 
{ 
    lock(_syncLock) 
    { 
     myWindow = new MyView(); 
     myWindow.Closed += new EventHandler(MyWindow_Closed); 

     myWindow.Width = width; 
     myWindow.Height = height; 
     myWindow.Top = top; 
     myWindow.Left = 0; 

     myWindow.ShowDialog(); 
    } 
}