上一篇讲到将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;
}
}
}