Solved

A tiny issue with ".NET Snap To Screen Form"

Posted on 2007-12-05
5
681 Views
Last Modified: 2013-12-16
Hi,

The code here is working very good when the ForBorderStyle is NOT set to "None":

http://www.codeproject.com/KB/vb/SnapForm.aspx

In my application, it's set to None... And I move the form by holding down the right mouse button and moving it. The code still partially work, but when I approach the taskbar from the clock side it's not completely sticked to the corners.

I tried to figure out what wrong with code but no luck (and no experience).

The complete code is attached. Just create a new project and paste it.

Your help would be greatly appreciated.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace WindowsFormsApplication11
{
    public partial class Form1 : Form
    {
        public const int WM_NCLBUTTONDOWN = 0xA1;
        public const int HT_CAPTION = 0x2;
 
        [DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd,
                         int Msg, int wParam, int lParam);
        [DllImportAttribute("user32.dll")]
        public static extern bool ReleaseCapture();
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
 
        }
 
        # region SnapToDesktopBorder
 
        private const int mSnapOffset = 35;
        private const int WM_WINDOWPOSCHANGING = 70;
 
        [StructLayout(LayoutKind.Sequential)]
        public struct WINDOWPOS
        {
            public IntPtr hwnd;
            public IntPtr hwndInsertAfter;
            public int x;
            public int y;
            public int cx;
            public int cy;
            public int flags;
        }
 
        protected override void WndProc(ref Message m)
        {
            // Listen for operating system messages
            switch (m.Msg)
            {
                case WM_WINDOWPOSCHANGING:
                    {
                        SnapToDesktopBorder(this, m.LParam, 0);
                    }
                    break;
            }
 
            base.WndProc(ref m);
        }
 
        public static void SnapToDesktopBorder(Form clientForm, IntPtr LParam, int widthAdjustment)
        {
            if (clientForm == null)
            {
                // Satisfies rule: Validate parameters
                throw new ArgumentNullException("clientForm");
            }
 
            // Snap client to the top, left, bottom or right desktop border
            // as the form is moved near that border.
 
            try
            {
                // Marshal the LPARAM value which is a WINDOWPOS struct
                WINDOWPOS NewPosition = new WINDOWPOS();
                NewPosition = (WINDOWPOS)System.Runtime.InteropServices.Marshal.PtrToStructure(LParam, typeof(WINDOWPOS));
 
                if (NewPosition.y == 0 || NewPosition.x == 0)
                {
                    return;
                    // Nothing to do!
                }
 
                // Adjust the client size for borders and caption bar
                Rectangle ClientRect = clientForm.RectangleToScreen(clientForm.ClientRectangle);
                ClientRect.Width += SystemInformation.FrameBorderSize.Width - widthAdjustment;
                ClientRect.Height += (SystemInformation.FrameBorderSize.Height + SystemInformation.CaptionHeight);
 
                // Now get the screen working area (without taskbar)
                Rectangle WorkingRect = Screen.GetWorkingArea(clientForm.ClientRectangle);
 
                // Left border
                if (NewPosition.x >= WorkingRect.X - mSnapOffset && NewPosition.x <= WorkingRect.X + mSnapOffset)
                {
                    NewPosition.x = WorkingRect.X;
                }
 
                // Get screen bounds and taskbar height
                // (when taskbar is horizontal)
                Rectangle ScreenRect = Screen.GetBounds(Screen.PrimaryScreen.Bounds);
                int TaskbarHeight = ScreenRect.Height - WorkingRect.Height;
 
                // Top border (check if taskbar is on top
                // or bottom via WorkingRect.Y)
                if (NewPosition.y >= -mSnapOffset && (WorkingRect.Y > 0 && NewPosition.y <= (TaskbarHeight + mSnapOffset)) || (WorkingRect.Y <= 0 && NewPosition.y <= (mSnapOffset)))
                {
                    if (TaskbarHeight > 0)
                    {
                        NewPosition.y = WorkingRect.Y;
                        // Horizontal Taskbar
                    }
                    else
                    {
                        NewPosition.y = 0;
                        // Vertical Taskbar
                    }
                }
 
                // Right border
                if (NewPosition.x + ClientRect.Width <= WorkingRect.Right + mSnapOffset && NewPosition.x + ClientRect.Width >= WorkingRect.Right - mSnapOffset)
                {
                    NewPosition.x = WorkingRect.Right - (ClientRect.Width + SystemInformation.FrameBorderSize.Width);
                }
 
                // Bottom border
                if (NewPosition.y + ClientRect.Height <= WorkingRect.Bottom + mSnapOffset && NewPosition.y + ClientRect.Height >= WorkingRect.Bottom - mSnapOffset)
                {
                    NewPosition.y = WorkingRect.Bottom - (ClientRect.Height + SystemInformation.FrameBorderSize.Height);
                }
 
                // Marshal it back
                System.Runtime.InteropServices.Marshal.StructureToPtr(NewPosition, LParam, true);
            }
            catch (ArgumentException ex)
            {
            }
        }
 
 
        # endregion
 
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }
    }
}

Open in new window

0
Comment
Question by:EEssam
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
5 Comments
 
LVL 30

Expert Comment

by:anarki_jimbel
ID: 20417110
OK, I spend hal an hour playing with your application and coud not find any wrong.
It sticks well from what I see (didn't use glasses however so could miss something).
Eventually if you have some extra gap/overlapping  -  just add/subtract couple of pixels.
0
 

Author Comment

by:EEssam
ID: 20417301
I'm using Windows XP SP2, not Vista. The problem is happening only when:

1. FormBorderStyle is set to "None":
2. The form is moved to the corner of Windows clock.
0
 
LVL 30

Expert Comment

by:anarki_jimbel
ID: 20422729
I'm using XP.
Did you wrote any code to move your form? Can you show it?
0
 

Author Comment

by:EEssam
ID: 20423078
The code to move the form is:

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }
0
 
LVL 30

Accepted Solution

by:
anarki_jimbel earned 500 total points
ID: 20424934
Try this code. For me it works fine.

It's pretty hard to explain why I use '-=" bordersize. However form with borders has
width = "form width without borders" plus
"border width" multiplied by 2. If in the firs case (your original code) we add
border width just once to get width (height) then "borderless" form should be
that minus "border width" multiplied by 2. It was just some logical conclusion.
                // Adjust the client size for borders and caption bar
                Rectangle ClientRect = clientForm.RectangleToScreen(clientForm.ClientRectangle);
                if (clientForm.FormBorderStyle != FormBorderStyle.None)
                {
                    ClientRect.Width += SystemInformation.FrameBorderSize.Width - widthAdjustment;
                    ClientRect.Height += (SystemInformation.FrameBorderSize.Height + SystemInformation.CaptionHeight);
 
                }
                else
                {
                    ClientRect.Width -= SystemInformation.FrameBorderSize.Width - widthAdjustment;
                    ClientRect.Height -= (SystemInformation.FrameBorderSize.Height);
 
                }

Open in new window

0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…
How to Install VMware Tools in Red Hat Enterprise Linux 6.4 (RHEL 6.4) Step-by-Step Tutorial

761 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question