В таких приложениях, как Проводник Windows и Internet Explorer, можно захватить расширенные области фреймов под заголовком и перетаскивать окна вокруг.
Для приложений WinForms формы и элементы управления так же близки к собственным API-интерфейсам Win32, которые они могут получить; можно просто переопределить обработчик WndProc()
в своей форме, обработать окно WM_NCHITTEST
и обмануть систему, подумав о щелчке по рамка была действительно нажатием на строку заголовка, возвращая HTCAPTION
. Я сделал это в своих приложениях WinForms для восхитительного эффекта.
В WPF я также могу реализовать аналогичный метод WndProc()
и привязать его к моему дескриптору окна WPF, расширяя рамку окна в клиентской области, например:
// In MainWindow
// For use with window frame extensions
private IntPtr hwnd;
private HwndSource hsource;
private void Window_SourceInitialized(object sender, EventArgs e)
{
try
{
if ((hwnd = new WindowInteropHelper(this).Handle) == IntPtr.Zero)
{
throw new InvalidOperationException("Could not get window handle for the main window.");
}
hsource = HwndSource.FromHwnd(hwnd);
hsource.AddHook(WndProc);
AdjustWindowFrame();
}
catch (InvalidOperationException)
{
FallbackPaint();
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case DwmApiInterop.WM_NCHITTEST:
handled = true;
return new IntPtr(DwmApiInterop.HTCAPTION);
default:
return IntPtr.Zero;
}
}
Проблема заключается в том, что, поскольку я слепо устанавливаю handled = true
и возвращаю HTCAPTION
, щелчок в любом месте, кроме значка окна или кнопок управления, вызывает перетаскивание окна. То есть все, выделенное красным цветом, вызывает перетаскивание. Это даже включает в себя ручки изменения размера по бокам окна (неклиентская область). Мои элементы управления WPF, а именно текстовые поля и элемент управления вкладкой, также прекращают получать клики в результате:
Я хочу только
- строка заголовка и
- области клиентской области...
- ... которые не заняты моими элементами управления
можно перетаскивать. То есть, я хочу, чтобы эти красные области были перетаскиваемыми (клиентская область + строка заголовка):
Как мне изменить мой метод WndProc()
и остальную часть моего окна XAML/code-behind, чтобы определить, какие области должны возвращать HTCAPTION
, а какие нет? Я думаю что-то вроде использования Point
для проверки местоположения клика относительно местоположений моих элементов управления, но я не уверен, как это сделать на WPF-земле.
РЕДАКТИРОВАТЬ [4/24]: один простой способ: иметь невидимый элемент управления или даже само окно, ответить на MouseLeftButtonDown
, вызвав DragMove()
в окне (см. Ответ Росса). Проблема в том, что по какой-то причине DragMove()
не работает, если окно максимизировано, поэтому оно не играет хорошо с Windows 7 Aero Snap. Поскольку я собираюсь для интеграции с Windows 7, это не приемлемое решение в моем случае.