Подключение к окну сообщений Windows в окне WPF добавляет белую границу внутри
Я пытаюсь создать окно WPF с WindowStyle="None"
(для пользовательских кнопок и без заголовка), которые нельзя изменить. Установка ResizeMode
в NoResize
удаляет границу аэра, которую я хочу сохранить.
Я мог бы установить свойства минимального/максимального размера и выполнить с ним, за исключением того, что:
- Курсоры изменения размеров все еще видны и
- Окно отображается в ответ на действие пользователя и соответствует его содержимому. Он отображает изображение, поэтому размер изменяется.
Итак, у меня есть простая схема, которая дает мне 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 );
}
}
В принципе;
- Отменить процедуру окна.
- Вызвать процедуру окна по умолчанию.
- Если сообщение
WM_NCHITTEST
, проверьте наличие результатов.
- Если это граница, верните обычный
HTBORDER
.
Это работает так же, как позволять мне сохранять границу окна аэронов и скрывать курсор изменения размера, но он добавляет белую границу размером ~ 5 пикселей к внутренней части моего окна.
Фактически, даже если я верну результат обработки окон по умолчанию в верхней части WndPrc
и ничего не делаю, граница все еще существует. Мне нужен другой цвет фона в моем окне, так что это не сработает для меня.
Любые идеи? Спасибо заранее, как всегда.
Ответы
Ответ 1
Когда вы добавляете свой крючок, вы должны обрабатывать только сообщения, которые вам нужны, и игнорировать остальные. Я считаю, что вы обрабатываете определенные сообщения дважды, так как вы вызываете 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;
}
Кроме того, я бы, вероятно, добавил hook в OnSourceInitialized, например:
protected override void OnSourceInitialized(EventArgs e) {
base.OnSourceInitialized(e);
IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
mainWindowSrc.AddHook(WndProc);
}
Ответ 2
Вы можете попробовать в любом месте приложения 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;
}
}
}
}
Надеюсь, что это поможет...:-)