확장창 프레임을 드래그하여 WPF 창을 이동 가능하게 하려면 어떻게 해야 합니까?
Windows 탐색기나 Internet Explorer와 같은 응용 프로그램에서는 제목 표시줄 아래의 확장 프레임 영역을 잡고 창을 드래그할 수 있습니다.
의 경우한.WinForms 어플리케이션에서는 Win32 API를 .API를 사용하다WndProc()
핸들러 형식으로 윈도 메시지를 처리하여 프레임 영역을 클릭하는 것이 제목 표시줄을 클릭하는 것이라고 생각하도록 시스템을 속입니다.HTCAPTION
WinForms 앱 、 WinForms 、 WinForms 、 WinForms 、 WinForms 、 WinForms 、 WinForms 。
에서는, WPF 「」, 「」의 「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()
및 하여 어떤 합니다.HTCAPTION
러면면 안는 는? ???'아까부터'라는을 하고 있어요.Point
컨트롤의 위치와 대조하여 클릭 위치를 확인합니다만, WPF 랜드에서는 어떻게 하면 좋을지 잘 모르겠습니다.
편집 [4/24]: 이를 위한 간단한 방법 중 하나는 보이지 않는 컨트롤, 심지어 창 자체도MouseLeftButtonDown
""를 DragMove()
(로스의 대답 참조) 창문에.문제는 어떤 이유에서인지DragMove()
윈도우가 최대화되면 동작하지 않기 때문에 Windows 7 Aero Snap에서는 잘 재생되지 않습니다.Windows 7 의 통합을 목표로 하고 있기 때문에, 저로서는 납득할 수 없는 솔루션입니다.
샘플코드
오늘 아침에 받은 이메일 덕분에, 저는 이 기능을 보여주는 샘플 앱을 만들도록 요청받았습니다.이 기능은 GitHub(또는 현재 아카이브된 CodePlex)에서 찾을 수 있습니다.저장소를 복제하거나 아카이브를 다운로드 및 추출한 다음 Visual Studio에서 열고 빌드 및 실행하면 됩니다.
애플리케이션 전체가 MIT 라이선스를 취득한 것이지만, 앱 코드를 완전하게 사용하는 것이 아니라, 그 코드의 일부를 떼어내, 자신의 코드에 넣을 수 있습니다.라이선스 때문에 그렇게 할 수 없는 것은 아닙니다.또, 애플리케이션의 메인 윈도우의 디자인이 위의 와이어 프레임과 전혀 비슷하지 않다는 것은 알고 있습니다만, 그 생각은 질문에 제시된 것과 같습니다.
이게 도움이 됐으면 좋겠네요!
단계별 솔루션
드디어 풀었어요.제프리 L 화이트리지가 나를 올바른 방향으로 인도해줘서 고마워!그의 대답은 받아들여졌다 왜냐하면 그것이 아니었다면 나는 해결책을 생각해 낼 수 없었을 것이기 때문이다.편집 [9/8]: 이 답변은 이제 더 완벽해 졌기 때문에 받아들여지고 있습니다; 나는 제프리의 도움 대신에 멋진 큰 현상금을 줄 것입니다.
후세를 위해서, 내가 그것을 한 방법은 다음과 같다(제프리씨의 답변이 적절할 경우 인용).
클릭 maybe "wParam, lParam"을 .
Point
(이것들)
는 '알다'에서 얻을 수 .lParam
WM_NCHITTEST
메세지.MSDN에서 설명한 바와 같이 커서의 x 좌표는 하위 단어이고 커서의 y 좌표는 상위 단어입니다.
화면 에 전화해야 .Visual.PointFromScreen()
윈도우 공간에 상대적인 좌표를 변환합니다.
인 방법을 정적인 방법이라고 .
VisualTreeHelper.HitTest(Visual,Point)
★★★★★this
및Point
오더가 가장 높은 .반환 값은 Z 순서가 가장 높은 컨트롤을 나타냅니다.
안 했다Grid
지배하다this
이치노마찬가지로 윈도우인지 아닌지를 확인하는 대신 결과가 늘인지 아닌지를 체크해야 했습니다.컨트롤에 영역null에 입니다.는 '', '아까', '아까'를 하는 것이었습니다.VisualTreeHelper.HitTest()
★★★★★★ 。
지금까지 말씀드린 바와 같이 제 절차를 따를 경우 두 가지 경고가 적용될 수 있습니다.
창 전체를 커버하지 않고 창 프레임을 부분적으로만 연장하는 경우 창 프레임이 채워지지 않은 직사각형을 클라이언트 영역 필러로 제어해야 합니다.
제 경우, 탭 컨트롤의 내용 영역은 다이어그램에 표시된 것처럼 직사각형 영역에 잘 맞습니다. 정도'를 할 .
Rectangle
또는 형상화Panel
적절한 색상으로 제어하고 칠합니다.이치노클라이언트 영역 필러에 관한 이 문제는 다음 문제로 이어집니다.
그리드 또는 기타 최상위 컨트롤에 확장된 창 프레임에 배경 텍스처 또는 그라데이션이 있는 경우 배경의 완전히 투명한 영역에서도 전체 그리드 영역이 적중 결과에 응답합니다(시각 레이어의 적중 테스트 참조).이 경우 그리드 자체에 대한 타격은 무시하고 그리드 내의 컨트롤에만 주의를 기울여야 합니다.
이 때문에,
// In MainWindow
private bool IsOnExtendedFrame(int lParam)
{
int x = lParam << 16 >> 16, y = lParam >> 16;
var point = PointFromScreen(new Point(x, y));
// In XAML: <Grid x:Name="windowGrid">...</Grid>
var result = VisualTreeHelper.HitTest(windowGrid, point);
if (result != null)
{
// A control was hit - it may be the grid if it has a background
// texture or gradient over the extended window frame
return result.VisualHit == windowGrid;
}
// Nothing was hit - assume that this area is covered by frame extensions anyway
return true;
}
이제 창의 비어 있는 영역만 클릭하고 끌어서 창을 이동할 수 있습니다.
하지만 그게 다가 아닙니다.에서는 창 도 이 하십시오.HTCAPTION
창문의 크기를 조정할 수 없게 되었습니다.
이를 수정하기 위해 커서가 클라이언트 영역과 비클라이언트 영역에 닿는지 확인해야 했습니다.이것을 확인하기 위해서는 함수를 사용하여 반환 여부를 확인해야 합니다.HTCLIENT
:
// In my managed DWM API wrapper class, DwmApiInterop
public static bool IsOnClientArea(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam)
{
if (uMsg == WM_NCHITTEST)
{
if (DefWindowProc(hWnd, uMsg, wParam, lParam).ToInt32() == HTCLIENT)
{
return true;
}
}
return false;
}
// In NativeMethods
[DllImport("user32.dll")]
private static extern IntPtr DefWindowProc(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam);
마지막으로, 최종 윈도우 프로시저 방법은 다음과 같습니다.
// In MainWindow
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case DwmApiInterop.WM_NCHITTEST:
if (DwmApiInterop.IsOnClientArea(hwnd, msg, wParam, lParam)
&& IsOnExtendedFrame(lParam.ToInt32()))
{
handled = true;
return new IntPtr(DwmApiInterop.HTCAPTION);
}
return IntPtr.Zero;
default:
return IntPtr.Zero;
}
}
다음은 여러분이 시도해 볼 수 있는 것입니다.
클릭 maybe "wParam, lParam"을 .Point
(이것들)
인 방법을 정적인 방법이라고 .VisualTreeHelper.HitTest(Visual,Point)
★★★★★this
및Point
오더가 가장 높은 .반환 값은 Z 순서가 가장 높은 컨트롤을 나타냅니다.창구라면, 의 창구인 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 네.HTCAPTION
른른른른른른른른... 지지마 。
행운을 빕니다.
WPF 앱에서 확장 Aero 글라스를 드래그할 수 있도록 하는 것과 같은 작업을 하고 싶다고 생각하고 있던 중, Google을 통해서 이 투고를 접하게 되었습니다.당신의 답변을 읽었지만, 더 간단한 것이 있는지 계속 찾아보기로 했습니다.
코드 집약도가 훨씬 낮은 솔루션을 찾았습니다.
컨트롤 뒤에 투명 항목을 만들고 창의 메서드를 호출하는 왼쪽 마우스 버튼 다운 이벤트 핸들러를 지정하기만 하면 됩니다.
확장 Aero 글라스 위에 표시되는 XAML 섹션은 다음과 같습니다.
<Grid DockPanel.Dock="Top">
<Border MouseLeftButtonDown="Border_MouseLeftButtonDown" Background="Transparent" />
<Grid><!-- My controls are in here --></Grid>
</Grid>
배후에 것(은 「」의 「」의 「」( 「」의 입니다.Window
등DragMove()
을 참조해 주세요.
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
바로 그거야!솔루션의 경우 직사각형이 아닌 드래그 가능 영역을 확보하려면 이러한 항목을 두 개 이상 추가해야 합니다.
간단한 방법은 스택 패널 또는 제목 표시줄 XAML에 필요한 모든 것을 작성하는 것입니다.
<StackPanel Name="titleBar" Background="Gray" MouseLeftButtonDown="titleBar_MouseLeftButtonDown" Grid.ColumnSpan="2"></StackPanel>
코드
private void titleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
언급URL : https://stackoverflow.com/questions/5493149/how-do-i-make-a-wpf-window-movable-by-dragging-the-extended-window-frame
'programing' 카테고리의 다른 글
wpf 형식의 텍스트로 위첨자 및 아래첨자 설정 (0) | 2023.04.16 |
---|---|
TextBlock에서 WPF 형식의 DateTime? (0) | 2023.04.16 |
MVVM을 사용하여 WPF ListView 항목에서 더블 클릭 이벤트 실행 (0) | 2023.04.11 |
EPplus를 사용한 Excel 문서 열기 (0) | 2023.04.11 |
모든 하위 디렉터리에 대해 git 풀 실행 (0) | 2023.04.11 |