Search code examples
c#winformsmaximize-window

Win form vanishes on maximizing


I am working on the UI for an application using Windows Form. I made a resizable borderless form after consulting this question and this one as well.

I have a multi screen computer. When i maximize on primary screen the form maximizes normally. If i move the form completely to my second screen and then use maximize , the form vanishes. After investigating i found that even though the property 'this.MaximizedBounds' for second screen is determined corretcly i.e {X=-1440,Y=0,Width=1440,Height=900} when i use the statement

this.WindowState = FormWindowState.Maximized; 

the form gets drawn at {X=-2880,Y=0,Width=1440,Height=900} as if for some reason the draw direction is reversed? given this I know I can programmatically determine the draw the form, but i was wondering is I am missing setting some additional property to make sure the draw direction is correct?

the issue with the programmatically maximized form is that the state of the form is still FormWindowState.Normal and i cant change it to FormWindowState.Maximized without causing the from to get redrawn in the wrong place

Code to make form Borderless

    protected override void WndProc(ref Message m)
    {
        const int RESIZE_HANDLE_SIZE = 10;

        switch (m.Msg)
        {
            case 0x0084/*NCHITTEST*/ :
                base.WndProc(ref m);

                if ((int)m.Result == 0x01/*HTCLIENT*/)
                {
                    Point screenPoint = new Point(m.LParam.ToInt32());
                    Point clientPoint = this.PointToClient(screenPoint);
                    if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
                    {
                        if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                            m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
                        else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                            m.Result = (IntPtr)12/*HTTOP*/ ;
                        else
                            m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
                    }
                    else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
                    {
                        if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                            m.Result = (IntPtr)10/*HTLEFT*/ ;
                        else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                            m.Result = (IntPtr)2/*HTCAPTION*/ ;
                        else
                            m.Result = (IntPtr)11/*HTRIGHT*/ ;
                    }
                    else
                    {
                        if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                            m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
                        else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                            m.Result = (IntPtr)15/*HTBOTTOM*/ ;
                        else
                            m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
                    }
                }
                return;
        }
        base.WndProc(ref m);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.Style |= 0x20000; // <--- use 0x20000
            cp.ClassStyle |= 0x08; 
            return cp;
        }
    }

Code to quit,maximize/restore,minimize

    private void button1_Click(object sender, EventArgs e)
    {
        Application.Exit();
    }
    private void button2_Click(object sender, EventArgs e)
    {
        if(this.WindowState==FormWindowState.Normal)
        {
            this.button2.Image = ((System.Drawing.Image)(Properties.Resources.Restore_Down));
            this.MaximizedBounds = Screen.FromHandle(this.Handle).WorkingArea;
            this.WindowState = FormWindowState.Maximized;

        }
        else if(this.WindowState == FormWindowState.Maximized)
        {
            this.WindowState = FormWindowState.Normal;
            this.button2.Image = ((System.Drawing.Image)(Properties.Resources.Maximize));
        }
    }
    private void button3_Click(object sender, EventArgs e)
    {
        this.WindowState = FormWindowState.Minimized;
    }

Solution

  • My assumption is that you are creating a borderless form and then creating your own toolbar. This maximizing, minimizing and restore can be achieved without WndProc. All one needs is three buttons and their click event handlers like this (it will work on multiple monitors as well):

        private void ClickMinimizeButton(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Minimized;
        }
    
        private void ClickRestoreButton(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Normal;
    
        }
    
        private void ClickMaximizeButton(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Maximized;
    
        }
    

    For moving the form around you will need to use WndProc. Specifically handle WM_NCLBUTTONDOWN windows message. This should be done in the MouseDown event handler.

            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
    

    Both ReleaseCapture and SendMessage are part of user32.dll.

    To resize, you will again need to make use to WndProc. However, since you have 2 monitors, you will need to get screen coordinates by your own. Following accepted response is from this question. It might help you get the correct coordinates.

    static class ControlExtensions
    {
        ///<summary>
        /// Returns the position of the point in screen coordinates of that control instead
        /// of the main-screen coordinates
        ///</summary>
        public static Point PointToCurrentScreen(this Control self, Point location)
        {
            var screenBounds = Screen.FromControl(self).Bounds;
            var globalCoordinates = self.PointToScreen(location);
            return new Point(globalCoordinates.X - screenBounds.X, globalCoordinates.Y - screenBounds.Y);
        }
    }