Подключение к циклу сообщений Windows в окне WPF добавляет белую рамку внутри - PullRequest
16 голосов
/ 16 июня 2011

Я пытаюсь создать окно WPF с WindowStyle="None" (для пользовательских кнопок и без заголовка), размер которого нельзя изменить.Установка 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.

Этоработает так, чтобы позволить мне сохранить границу аэроокна и скрыть курсор (и) изменения размера, но добавляет белую рамку ~ 5 пикселей внутрь моего окна.

На самом деле, даже если я возвращаю результат процедуры Windows по умолчанию вверху WndPrc и ничего не делаю, граница там все еще .Мне нужен другой цвет фона для моего окна, так что это не сработает для меня.

Есть идеи?Заранее спасибо как всегда.

Ответы [ 2 ]

10 голосов
/ 16 июня 2011

Когда вы добавляете свой хук, вы должны обрабатывать только те сообщения, которые вам нужны, и игнорировать остальные. Я полагаю, что вы обрабатываете определенные сообщения дважды, поскольку вы вызываете DefWindowProc, но никогда не устанавливаете для обработанного параметра значение 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);
}
3 голосов
/ 17 февраля 2012

Вы можете попробовать из любого места в приложении 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;
                }
            }
        }
    }

Надеюсь, это поможет ... :-)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...