在WPF窗口中挂接到Windows消息循环会在内部添加白色边框



我正在尝试创建一个带有WindowStyle="None"(用于自定义按钮且没有标题)的WPF窗口,该窗口无法调整大小。将ResizeMode设置为NoResize将删除我想要保留的空气边界。

我可以设置最小/最大大小属性并完成它,除了:

  1. 调整大小的光标仍然可见,并且
  2. 该窗口是响应用户操作而显示的,并适合其内容。它显示一个图像,因此大小会发生变化

所以,我有一个简单的方案,可以让我99%的时间:

public class BorderedWindowNoResize : Window
{
    [DllImport( "DwmApi.dll" )]
    public static extern int DwmExtendFrameIntoClientArea(
        IntPtr hwnd,
        ref MARGINS pMarInset );
    [DllImport( "user32.dll", CharSet = CharSet.Auto )]
    public static extern IntPtr DefWindowProc(
        IntPtr hWnd,
        int msg,
        IntPtr wParam,
        IntPtr lParam );
    public BorderedWindowNoResize()
    {           
        Loaded += BorderedWindowNoResize_Loaded;
    }
    private void BorderedWindowNoResize_Loaded( object sender, RoutedEventArgs e )
    {           
        IntPtr mainWindowPtr = new WindowInteropHelper( this ).Handle;
        HwndSource mainWindowSrc = HwndSource.FromHwnd( mainWindowPtr );            
        mainWindowSrc.AddHook( WndProc );
    }
    private IntPtr WndProc( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled )
    {           
        var htLocation = DefWindowProc( hwnd, msg, wParam, lParam ).ToInt32();
        if( msg == (uint)WM.NCHITTEST )
        {
            handled = true;
            switch( htLocation )
            {
                case (int)HitTestResult.HTBOTTOM:
                case (int)HitTestResult.HTBOTTOMLEFT:
                case (int)HitTestResult.HTBOTTOMRIGHT:
                case (int)HitTestResult.HTLEFT:
                case (int)HitTestResult.HTRIGHT:
                case (int)HitTestResult.HTTOP:
                case (int)HitTestResult.HTTOPLEFT:
                case (int)HitTestResult.HTTOPRIGHT:
                    htLocation = (int)HitTestResult.HTBORDER;
                    break;
            }               
        }
        return new IntPtr( htLocation );
    }
}

基本上;

  1. 覆盖窗口过程
  2. 调用默认窗口过程
  3. 如果消息是WM_NCHITTEST,请检查边界结果
  4. 如果是边界,则返回常规HTBORDER

这可以让我保留aero窗口边界并隐藏调整大小的光标,但它在窗口内部添加了一个~5像素的白色边界。

事实上,即使我在WndPrc的顶部返回默认的windows过程结果,并且不做任何其他操作,边界仍然是。我需要在我的窗口上使用不同的背景色,所以这对我不起作用。

有什么想法吗?一如既往地提前感谢。

添加钩子时,应该只处理需要处理的消息,而忽略其他消息。我相信您正在处理某些消息两次,因为您调用了DefWindowProc,但从未将handled参数设置为true。

所以在你的情况下,你会使用:

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
    if (msg == (uint)WM.NCHITTEST) {
        handled = true;
        var htLocation = DefWindowProc(hwnd, msg, wParam, lParam).ToInt32();
        switch (htLocation) {
            case (int)HitTestResult.HTBOTTOM:
            case (int)HitTestResult.HTBOTTOMLEFT:
            case (int)HitTestResult.HTBOTTOMRIGHT:
            case (int)HitTestResult.HTLEFT:
            case (int)HitTestResult.HTRIGHT:
            case (int)HitTestResult.HTTOP:
            case (int)HitTestResult.HTTOPLEFT:
            case (int)HitTestResult.HTTOPRIGHT:
                htLocation = (int)HitTestResult.HTBORDER;
                break;
        }
        return new IntPtr(htLocation);
    }
    return IntPtr.Zero;
}

此外,我可能会在OnSourceInitialized覆盖中添加钩子,如下所示:

protected override void OnSourceInitialized(EventArgs e) {
    base.OnSourceInitialized(e);
    IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
    HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
    mainWindowSrc.AddHook(WndProc);
}

您可以在WPF应用程序的任何地方尝试

ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage);

和:

// ******************************************************************
private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled)
{
    if (!handled)
    {
        if (msg.message == WmHotKey)
        {
            HotKey hotKey;
            if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey))
            {
                if (hotKey.Action != null)
                {
                    hotKey.Action.Invoke(hotKey);
                }
                handled = true;
            }
        }
    }
}

最新更新