WPF直接用Window.Close直接關閉窗口導致不能完全退出的問題


更新:2018 2. 27

這是我兩年前寫的文章,當時沒考慮到debug環境下的問題,事實上debug環境下才會有AdornerLayer,這個問題應該不是單純由AdornerLayer引起的

剛好今年一月份的時候有個人艾特了我http://bbs.csdn.net/topics/392301858,而我已經很久沒寫WPF了

請參考提問者最后一個回答:

但網絡上也沒有別的猜測和處理辦法了,只有在窗體里面建立線程句柄 之后 再啟動線程。然后 overrides onclosing里面  關掉沒退出的線程就可以了。程序可以正常退出。

 


 

前幾天我在CSDN扔了一個問題,基本描述一下:寫了一段這樣的代碼,來實現獲取Control的template,卻發現一個這樣的問題,就是當我打開了一個window以后,手動調用Close(),窗口的確是消失了,但是當我關閉了主窗口以后,卻發現程序沒有退出。

 1 private void ControlTypeSelectingBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
 2         {
 3             try
 4             {
 5                 Type type = ControlTypeSelectingBox.SelectedItem as Type;
 6 
 7                 if (type == null)
 8                     throw new ArgumentNullException("Type is null");
 9 
10                 ConstructorInfo info = type.GetConstructor(System.Type.EmptyTypes);
11                 Control control = info.Invoke(null) as Control;
12 
13                 Window window = control as Window;
14                 Window windowAdnore = null;
15 
16                 //注意,下面必須要有打開窗口或者把控件放入grid的操作,這樣才能讓下面的template正確顯示出來
17                 if (window != null)
18                 {
19                     window.WindowState = System.Windows.WindowState.Minimized;
20                     window.ShowInTaskbar = false;
21                     window.Owner = this;
22                     window.Show();
23 
24                     windowAdnore = Application.Current.Windows[Application.Current.Windows.Count - 1];
25                 }
26                 else
27                 {
28                     control.Visibility = Visibility.Collapsed;
29                     grid.Children.Add(control);
30                 }
31                  
32                 ControlTemplate template = control.Template;
33 
34                 XmlWriterSettings settings = new XmlWriterSettings();
35                 settings.Indent = true;
36 
37                 StringBuilder strbuilder = new StringBuilder();
38                 XmlWriter writer = XmlWriter.Create(strbuilder, settings);
39                 XamlWriter.Save(template, writer);
40 
41                 txtTemplateBrowser.Text = strbuilder.ToString();
42 
43                 if (window == null)
44                     grid.Children.Remove(control);
45                 else
46                 {
47                     window.Close();
48                     windowAdnore?.Close();
49                 }
50             }
51             catch (Exception ex)
52             {
53                 txtTemplateBrowser.Text = "<< Error generating template:" + ex.Message + ">>";
54             }
55         }

 

 

 

  但是如果我不手動調用Close(),而是讓window調用Show以后我點窗口上的關閉鍵,那就可以徹底退出了(手動點擊×以后再關閉主窗口程序可以徹底退出了),然后我再在主窗口重寫OnClosed方法

 1 protected override void OnClosed(EventArgs e)  2 {  3        var collections = Application.Current.Windows;  4  
 5         foreach (Window window in collections)  6  {  7                if (window != this)  8  window.Close();  9  } 10  
11          base.OnClosed(e); 12 }

  這樣居然能正常退出了!

 

  反正問了好多天沒人回答,自己再試了幾次,發現原來是這樣的:

  

  這是打開窗口並且Show以后Application.Current.Windows集合里面的東西,這下你明白了吧,第一項就是主窗口,第三項就是我們新創建的窗口,那么第二項和第四項是什么東西?

  網上怎么查都查不出這是什么(果然WPF用的人還是比較少呀),去翻了一下MSDN的文檔:

  

  想了一下,應該是WPF每次打開窗口的時候,首先打開窗口的實例,如果要Show的時候,那么就加載Window的模板(這也就是為什么Window一定要Show才能看見它的控件模板的原因),並且創建一個不可見的AdornerLayer,當我們手動去關閉Window的時候(按那個關閉按鈕),是會關閉掉AdornerLayer的,但是直接Close不會。

 

 

 

  不過這個神奇的坑真的沒有人發現過嗎?(好奇)

  貼正確關閉的代碼:

 1         private void ControlTypeSelectingBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
 2         {
 3             try
 4             {
 5                 Type type = ControlTypeSelectingBox.SelectedItem as Type;
 6 
 7                 if (type == null)
 8                     throw new ArgumentNullException("Type is null");
 9 
10                 ConstructorInfo info = type.GetConstructor(System.Type.EmptyTypes);
11                 Control control = info.Invoke(null) as Control;
12 
13                 Window window = control as Window;
14                 Window windowAdnore = null;
15 
16                 //注意,下面必須要有打開窗口或者把控件放入grid的操作,這樣才能讓下面的template正確顯示出來
17                 if (window != null)
18                 {
19                     window.WindowState = System.Windows.WindowState.Minimized;
20                     window.ShowInTaskbar = false;
21                     window.Owner = this;
22                     window.Show();
23 
24                     windowAdnore = Application.Current.Windows[Application.Current.Windows.Count - 1];
25                 }
26                 else
27                 {
28                     control.Visibility = Visibility.Collapsed;
29                     grid.Children.Add(control);
30                 }
31                  
32                 ControlTemplate template = control.Template;
33 
34                 XmlWriterSettings settings = new XmlWriterSettings();
35                 settings.Indent = true;
36 
37                 StringBuilder strbuilder = new StringBuilder();
38                 XmlWriter writer = XmlWriter.Create(strbuilder, settings);
39                 XamlWriter.Save(template, writer);
40 
41                 txtTemplateBrowser.Text = strbuilder.ToString();
42 
43                 if (window == null)
44                     grid.Children.Remove(control);
45                 else
46                 {
47                     window.Close();
48                     windowAdnore?.Close();
49                 }
50             }
51             catch (Exception ex)
52             {
53                 txtTemplateBrowser.Text = "<< Error generating template:" + ex.Message + ">>";
54             }
55         }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM