이제 WPF로 바꿔보세요 (15)

DragMove의 문제



DragMove 편리합니다만 하고 싶다고 생각하고 있는 Screen의 인연에의 스냅이 잘 되지 않아.
하고 싶은 것은 일정 이상 가장자리에 가까워지면 가장자리에 흡착시킨다는 것.
VB의 경우
①드래그의 개시시에 윈도우의 TOP·LEFT를 취해 둔다
② 드래그 중에는 왼쪽 버튼을 누르고 있는 동안 마진의 사이즈를 가산하여 커서 포지션을 산출하고, 윈도우를 산출 좌표에 로케이트 한다는 같은 구현으로 OK였습니다. VB↓
    Private Sub DragStart()
        Dragging = True
        offsetPos.X = MousePosition.X - Left
        offsetPos.Y = MousePosition.Y - Top
    End Sub

    Private Sub Drag(e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then
            If Dragging = True Then
                Me.Location = GetPos(offsetPos)
            End If
        End If
    End Sub

    Private Sub DragEnd()
        If Dragging = True Then
            Me.Location = GetPos(offsetPos)
        End If
        Dragging = False
    End Sub

    Private Function GetPos(aPos) As Point
        GetPos.Y = MousePosition.Y - aPos.Y
        GetPos.X = MousePosition.X - aPos.X

        'スクリーンフレームへの吸着
        If GetPos.Y < marginsize Then GetPos.Y = 0
        If GetPos.X < marginsize Then GetPos.X = 0
        If (GetPos.Y + Height + marginsize) > h Then GetPos.Y = h - Height
        If (GetPos.X + Width + marginsize) > w Then GetPos.X = w - Width
    End Function

처음 DragMove를 사용하지 않고 그대로 C#으로 바꿔 보았습니다만, 빠른 드래그 조작에 화면이 붙어 이것이 아닙니다. 에서 화면에서 커서 아웃하면, 거기에서 제어가 손실됩니다.
아무래도 사용할 수 있을 것 같지 않기 때문에, 역시 반응이 좋은 DragMove를 사용해, 이하와 같은 순서로 변경.
드래그 중인 ChangeLocation 이벤트 내에서 윈도우의 상하 좌우 좌표가 Screen의 Working 영역에 스냅 마진을 가산·감산한 범위내가 되었을 경우, 스냅 후의 지정값으로 윈도우 위치를 변경.
C#에서는 이런 느낌으로 ↓ (G.SR에는 화면 해상도가 들어 있습니다. 1.25 같은)

        private void Window_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ButtonState != MouseButtonState.Pressed) return;
            DragMove(); //ここからDragMove
        }

        private void Window_MouseUp(object sender, MouseButtonEventArgs e)
        {
            //Draggingの終了
            if (G.isDragging == true) G.isDragging = false;
        }

        private void Window_LocationChanged(object sender, EventArgs e)
        {
            if(G.isTransing == false)   //画面TransitionによるLocationChangedは無視する
            {
                //ドラッグ中の場合はG.isDragging = trueにしておくことで最初のクリックイベントを回避
                if (Mouse.LeftButton == MouseButtonState.Pressed) G.isDragging = true;
                    else G.isDragging = false;

                //スクリーン縁への吸着
                var NewPos = GetPos();
                var hwnd = new WindowInteropHelper(this).Handle;
                NativeMethods.SetWindowPos(hwnd, IntPtr.Zero, (int)Math.Round(NewPos.X), (int)Math.Round(NewPos.Y),
                            (int)Math.Round(Width * G.SR), (int)Math.Round(Height * G.SR), Consts.SWP_NOZORDER);
            }
        }

        private Point GetPos()
        {
            var NewWindowPos = new Point();

            NewWindowPos.X = this.Left * G.SR;  
            NewWindowPos.Y = this.Top * G.SR;
            if (NewWindowPos.X < G.marginsize) NewWindowPos.X = 0;  //左辺への吸着
            if (NewWindowPos.Y < G.marginsize) NewWindowPos.Y = 0;  //上辺への吸着
            if (NewWindowPos.X + (Width * G.SR) + G.marginsize > G.SW) NewWindowPos.X = G.SW - (Width * G.SR);  //右辺への吸着
            if (NewWindowPos.Y + (Height * G.SR) + G.marginsize > G.SH) NewWindowPos.Y = G.SH - (Height * G.SR);  //底辺への吸着
            return NewWindowPos;
        }

결과적으로 가장자리에 대한 스냅은 성공했지만 테두리 밖으로 드래그하면 계속 깜박임이 발생합니다. 본 느낌, DragMove에 의해 일단 테두리 밖에 묘화해, 그 뒤 LocationChanged내의 SetWindowPos로 테두리내에 묘화하고 있는 바람.
해결책 생각하지 않기 때문에, 이대로 가는 것에.

좋은 웹페이지 즐겨찾기