class WindowSnapBehavior : Behavior<Window>
{
#region EnableSnap 依存関係プロパティ
public double SnapDistance
{
get { return (double)GetValue(SnapDistanceProperty); }
set { SetValue(SnapDistanceProperty, value); }
}
public static readonly DependencyProperty SnapDistanceProperty =
DependencyProperty.Register("SnapDistance", typeof(double), typeof(WindowSnapBehavior), new PropertyMetadata(7.0));
#endregion
#region EnableSnap 依存関係プロパティ
public bool EnableSnap
{
get { return (bool)GetValue(EnableSnapProperty); }
set { SetValue(EnableSnapProperty, value); }
}
public static readonly DependencyProperty EnableSnapProperty =
DependencyProperty.Register("EnableSnap", typeof(bool), typeof(WindowSnapBehavior), new PropertyMetadata(true));
#endregion
protected override void OnAttached()
{
AssociatedObject.LocationChanged += AssociatedObject_LocationChanged;
}
protected override void OnDetaching()
{
AssociatedObject.LocationChanged -= AssociatedObject_LocationChanged;
}
void AssociatedObject_LocationChanged(object sender, EventArgs e)
{
if (!EnableSnap) { return; }
var window = AssociatedObject;
if (window.WindowState != WindowState.Normal) { return; }
// DPIから物理ピクセルへ変換する行列を取得してそれぞれの長さを変換
var mat = PresentationSource.FromVisual(window).CompositionTarget.TransformToDevice;
var scaledTopLeft = mat.Transform(new Point(window.Left, window.Top));
var scaledBottomRight = mat.Transform(new Point(window.Left + window.ActualWidth, window.Top + window.ActualHeight));
var scaledSnapDisatance = mat.Transform(new Point(SnapDistance, SnapDistance));
var scaledSize = scaledBottomRight - scaledTopLeft;
var screen = System.Windows.Forms.Screen.FromPoint(new System.Drawing.Point((int)scaledTopLeft.X, (int)scaledTopLeft.Y));
var newTop = scaledTopLeft.Y;
var newLeft = scaledTopLeft.X;
// 横方向の調整
if (Math.Abs(screen.Bounds.Left - scaledTopLeft.X) <= scaledSnapDisatance.X) {
newLeft = screen.Bounds.Left;
}
else if (Math.Abs(screen.Bounds.Right - scaledBottomRight.X) <= scaledSnapDisatance.X) {
newLeft = screen.Bounds.Right - scaledSize.X;
}
// 縦方向の調整
if (Math.Abs(screen.Bounds.Top - scaledTopLeft.Y) <= scaledSnapDisatance.Y) {
newTop = screen.Bounds.Top;
}
else if (Math.Abs(screen.Bounds.Bottom - scaledBottomRight.Y) <= scaledSnapDisatance.Y) {
newTop = screen.Bounds.Bottom - scaledSize.Y;
}
window.Left = newLeft;
window.Top = newTop;
}
}