繁体   English   中英

如果打开了OpenFileDialog,则阻止关闭WPF窗口(来自其他线程)

[英]Block closing WPF window (from a different thread) if OpenFileDialog is open

为了在您提到最明显的选择之前清除问题,我已经在调用ShowDialog而不是Show方法!

如果要打开OpenFileDialog,我想阻止WPF窗口的关闭(从其他线程调用)。

这是我的代码(减少显示我的问题):

public class FooWindow : Window
{
    public FooWindow()
    {
        InitializeComponent();
        this.Closing += OnClosing;    
    }

    public void OpenDialogAndCloseMe()
    {
        var ofd = new OpenFileDialog();

        Thread th = new Thread(() => CloseMe());
        th.Start();

        ofd.ShowDialog(this);
    }

    public void CloseMe()
    {
        System.Threading.Thread.Sleep(2000); //give the OpenFileDialog time to pop up...

        //since this method gets called from a different thread invoke it...
        this.Dispatcher.Invoke(() => this.Close());
    }

    private void OnClosing(object sender, CancelEventArgs e)
    {
        //check if OpenFileDialog is still open and block the close...
        e.Cancel = true;
    }
}

我面临的问题是OnClosing部分,如何获取OpenFileDialog(或在这种情况下的任何其他Dialog)。

我在网上搜索并发现Win32方法,例如:

[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr window, EnumedWindow callback, ArrayList lParam);

[DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

我都尝试过它们,但它们返回了0个孩子,有什么想法吗?

这是到目前为止我尝试过的完整代码:

//replace the above OnClosing with this implementation... all 3 return false
private void OnClosing(object sender, CancelEventArgs e)
{
    //check if OpenFileDialog is still open and block the close...
    var hWnd = new WindowInteropHelper(this).Handle;

    if (WindowHandling.GetChildren(hWnd).Any())
        e.Cancel = true;

    if (WindowHandling.GetChildrenV2(hWnd).Any())
        e.Cancel = true;

    if (WindowHandling.GetChildrenV3(hWnd).Any())
        e.Cancel = true;
}

public static class WindowHandling
{
    private delegate bool EnumedWindow(IntPtr handleWindow, ArrayList handles);

    [DllImport("user32")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr window, EnumedWindow callback, ArrayList lParam);

    [DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]
    static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    private static bool GetWindowHandle(IntPtr windowHandle, ArrayList windowHandles)
    {
        windowHandles.Add(windowHandle);
        return true;
    }

    public static IEnumerable<IntPtr> GetChildren(IntPtr hWnd)
    {
        if (hWnd == IntPtr.Zero)
            return Enumerable.Empty<IntPtr>();

        var x = new WindowHandleInfo(hWnd);
        return x.GetAllChildHandles();
    }

    public static IEnumerable<IntPtr> GetChildrenV2(IntPtr hWnd)
    {
        var windowHandles = new ArrayList();
        EnumedWindow callBackPtr = GetWindowHandle;
        EnumChildWindows(hWnd, callBackPtr, windowHandles);

        return windowHandles.OfType<IntPtr>();
    }
    public static IEnumerable<IntPtr> GetChildrenV3(IntPtr hParent)
    {
        var result = new List<IntPtr>();
        var ct = 0;
        var maxCount = 100;
        var prevChild = IntPtr.Zero;

        while (true && ct < maxCount)
        {
            var currChild = FindWindowEx(hParent, prevChild, null, null);
            if (currChild == IntPtr.Zero)
                break;

            result.Add(currChild);
            prevChild = currChild;
            ++ct;
        }

        return result;
    }

    //http://stackoverflow.com/questions/1363167/how-can-i-get-the-child-windows-of-a-window-given-its-hwnd
    private class WindowHandleInfo
    {
        private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);

        private readonly IntPtr _mainHandle;

        public WindowHandleInfo(IntPtr handle)
        {
            _mainHandle = handle;
        }

        public IEnumerable<IntPtr> GetAllChildHandles()
        {
            var childHandles = new List<IntPtr>();

            var gcChildhandlesList = GCHandle.Alloc(childHandles);
            var pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);

            try
            {
                var childProc = new EnumWindowProc(EnumWindow);
                var x = EnumChildWindows(this._mainHandle, childProc, pointerChildHandlesList);
                if (x == false)
                {
                    var error = Marshal.GetLastWin32Error();
                }
            }
            finally
            {
                gcChildhandlesList.Free();
            }

            return childHandles;
        }

        private static bool EnumWindow(IntPtr hWnd, IntPtr lParam)
        {
            var gcChildhandlesList = GCHandle.FromIntPtr(lParam);

            if (gcChildhandlesList.Target == null)
                return false;

            var childHandles = gcChildhandlesList.Target as List<IntPtr>;
            if (childHandles != null)
                childHandles.Add(hWnd);

            return true;
        }
    }
}

您可以通过布尔值跟踪来解决此问题(无论它是否打开):

bool dialogOpen = false;

public void OpenDialogAndCloseMe()
{
    var ofd = new OpenFileDialog();

    Thread th = new Thread(() => CloseMe());
    th.Start();

    dialogOpen = true;
    ofd.ShowDialog(this);
    dialogOpen = false;
}


private void OnClosing(object sender, CancelEventArgs e)
{
    //check if OpenFileDialog is still open and block the close...
    if(dialogOpen)
    {
        e.Cancel = true;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM