1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

今更ながらWPFに置き換えてみる(15)

Last updated at Posted at 2020-04-27

#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で枠内に描画している風。
解決策思いつかないので、このままでいくことに。
listview_itemdelete7.gif

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?