1. 程式人生 > >WPF中Popup的幾個問題

WPF中Popup的幾個問題

gate png shell child bubuko tor preview mouse des

原文:WPF中Popup的幾個問題

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

WPF中Popup的幾個問題