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