要用popup控件來解決一些問題。就此帶來了一批問題。
問題一、 在popup外任意位置點擊時要能關閉popup,這個本來簡單,只要加上StaysOpen=false就可以了。但我的popup中有個OpenFileDialog控件,這個控件窗口一打開,popup就被關閉了。
解決:
在btnOpenFile按鈕的PreviewMouseLeftButtonDown事件里添加了
((Popup)((FrameworkElement)this.Parent).Parent).StaysOpen = true;
問題二、 StaysOpen設置為True后,點擊按鈕變成了這樣。popup是TopMost的,擋在了文件窗口前面。
解決:
無法簡單解決這個問題,只好采用github上的一個NonTopmostPopup自定義控件取代Popup。
為了在關閉文件選擇窗口后popup仍然能夠在鼠標點擊App任意位置時被關閉,在btnOpenFile按鈕的Click事件里添加了
((Popup)((FrameworkElement)this.Parent).Parent).StaysOpen = false;
問題三、上述做法的結果是,如果雙擊文件名時的鼠標位置在popup區域以外,popup還是會直接關閉。因為雙擊位置的主窗口控件雖然被文件對話框遮擋,但仍會觸發MouseLeftButtonUp(或MouseUp)事件,這可能算是文件對話框的一個bug。我猜是因為雙擊實際上是在第二次點擊的MouseDown事件發生后就生效,對話框就關閉了,再往后還有MouseUp事件,卻已經處於沒有遮擋的裸奔狀態了,當然控件們紛紛響應。
沒辦法,想workaround吧。我的做法是取消按鈕Click事件StaysOpen=false,改在主窗口的MouseLeftButtonDown中加下面的代碼遍歷控件,遇到popup就設置StaysOpen=false。
private void TheShell_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { FindPopupAndClose(TheShell); } // Enumerate all the descendants of the visual object. static public void FindPopupAndClose(Visual myVisual) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++) { // Retrieve child visual at specified index value. Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i); // Do processing of the child visual object. if (childVisual is Popup) ((Popup)childVisual).StaysOpen = false; // Enumerate children of the child visual object. FindPopupAndClose(childVisual); } }
問題四、一些情況下,我需要popup StaysOpen=false,並且能跟隨主窗口移動而移動(默認情況popup是不動的)。
解決:
參考StackOverFlow上的帖子,在codebehind加下面事件:
public partial class View1 : UserControl { // Constructor public View1() { InitializeComponent(); // Window.GetWindow() will return Null if you try to call it here! // Wire up the Loaded handler instead this.Loaded += new RoutedEventHandler(View1_Loaded); } /// Provides a way to "dock" the Popup control to the Window /// so that the popup "sticks" to the window while the window is dragged around. void View1_Loaded(object sender, RoutedEventArgs e) { Window w = Window.GetWindow(popupTarget); // w should not be Null now! if (null != w) { w.LocationChanged += delegate(object sender2, EventArgs args) { var offset = myPopup.HorizontalOffset; // "bump" the offset to cause the popup to reposition itself // on its own myPopup.HorizontalOffset = offset + 1; myPopup.HorizontalOffset = offset; }; // Also handle the window being resized (so the popup's position stays // relative to its target element if the target element moves upon // window resize) w.SizeChanged += delegate(object sender3, SizeChangedEventArgs e2) { var offset = myPopup.HorizontalOffset; myPopup.HorizontalOffset = offset + 1; myPopup.HorizontalOffset = offset; }; } } }
小小的popup這才算整聽話了。