更新: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 }