把WPF Dialog转成WinForm Dialog需要注意的问题续
上一篇讲到将WPF的窗口转为WinForm窗口需要注意的问题,这里给出了另一种解决方案,闲话不说,请看代码:
//============================================================================== // File Name : WpfModalDialogFixer.cs // // Copyright (C) 2010 GrapeCity Inc. All rights reserved. // // Distributable under LGPL license. // //============================================================================== // <fileinformation> // <summary> // This file defines the class WpfModalDialogFixer for solve the problem as below: // When showing a modal dialog which ShowTaskBar is false, first deactive the application the activate it again. // The modal dialog would be at behind of MainWindow. // </summary> // <author name="WinkingZhang" mail="Winking.Zhang@GrapeCity.com"/> // <seealso ref=""/> // <remarks> // // </remarks> // </fileinformation> // <history> // <record date="10/21/2010 6:07:04 PM" author="WinkingZhang" revision="1.00.000"> // Create the file and define the class. // </record> // </history> using System; using System.Threading; using System.Windows; using System.Windows.Interop; using System.Runtime.InteropServices; namespace GrapeCity.Windows { /// <summary> /// Represents the <see cref="WpfModalDialogFixer"/> class. /// </summary> public class WpfModalDialogFixer { [ThreadStatic] private static WpfModalDialogFixer _fixer; private static readonly object _rootSync = new object(); static WpfModalDialogFixer() { ComponentDispatcher.EnterThreadModal += new EventHandler(OnComponentDispatcherEnterThreadModal); ComponentDispatcher.LeaveThreadModal += new EventHandler(OnComponentDispatcherLeaveThreadModal); } private WpfModalDialogFixer() { } static void OnComponentDispatcherLeaveThreadModal(object sender, EventArgs e) { if (WpfModalDialogFixer.Current.Enable) { HwndSource src = HwndSource.FromVisual(Application.Current.MainWindow) as HwndSource; if (src != null) { src.RemoveHook(new HwndSourceHook(OnComponentDispatcherThreadPreprocessMessage)); } } } static IntPtr OnComponentDispatcherThreadPreprocessMessage(IntPtr hwnd, int message, IntPtr wparam, IntPtr lparam, ref bool handled) { // Need take care the message: WM_SETFOCUS, and if now in Modal dialog mode. if (message == 0x7 && ComponentDispatcher.IsThreadModal) { bool actived = false; foreach (Window w in Application.Current.Windows) { HwndSource src = HwndSource.FromVisual(w) as HwndSource; if (src != null /*&& src.Handle != hwnd*/) { if (IsWindowEnabled(src.Handle)) { w.Activate(); actived = true; break; } } } if (!actived) // in this case, caused by MessageBox.Show(...) { //TODO: how to handle? } handled = true; // set handled to prevent default implement. } return IntPtr.Zero; } static void OnComponentDispatcherEnterThreadModal(object sender, EventArgs e) { if (WpfModalDialogFixer.Current.Enable) { HwndSource src = HwndSource.FromVisual(Application.Current.MainWindow) as HwndSource; if (src != null) { src.AddHook(new HwndSourceHook(OnComponentDispatcherThreadPreprocessMessage)); } } } [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool IsWindowEnabled(IntPtr hwnd); public static WpfModalDialogFixer Current { get { if (_fixer == null) { lock (_rootSync) { if (_fixer == null) { _fixer = new WpfModalDialogFixer(); } } } return _fixer; } } public bool Enable { get; set; } } }