要用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; }; } } }