How to set minimum Size of Custom Control with “CreateParams”

a 夏天 提交于 2020-08-26 10:19:11

问题


I am trying to make a draggable, resizable panel with a minimum size. I have used CreateParams for the Resize and now the Minimum size property doesn't work.

My question is how to set the minimum size in this case?

I have tried Limit resizable dimensions of a custom control (c# .net) but can't get it to work.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Move_Resize_Controls
{
    class MyPanel: Panel
    {
        // For Moving Panel "Drag the Titlebar and move the panel"
        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();

        // Constructor
        public MyPanel()
        {
            typeof(MyPanel).InvokeMember("DoubleBuffered", BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, this, new object[] { true }); // Double buffer MyPanel
            TitleBar(); // TitleBar
        }

        // Resize function for the panel - "Resizable Panel"
        protected override CreateParams CreateParams
        {
            get
            {
                var cp = base.CreateParams;
                cp.Style |= (int)0x00040000L;  // Turn on WS_BORDER + WS_THICKFRAME
                //cp.Style |= (int)0x00C00000L;  // Move
                return cp;
            }
        }

        // The Title Bar
        private void TitleBar()
        {
            Panel titleBar = new Panel();
            titleBar.BackColor = Color.Black;
            titleBar.Size = new Size(this.Size.Width, 20);
            titleBar.Dock = DockStyle.Top;
            this.Controls.Add(titleBar);

            titleBar.MouseDown  += new System.Windows.Forms.MouseEventHandler(this.MouseDownTitleBar); // Mouse Down - Event
            typeof(Panel).InvokeMember("DoubleBuffered", BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, titleBar, new object[] { true }); // Double Buffered 
        }

        // Move Panel
        private void MouseDownTitleBar(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }
    }
}

回答1:


Set the MinimumSize() property to want you want for your control (as normal through the IDE or through code), then add the code below to your control to trap the WM_GETMINMAXINFO message and override the minimum size as the control is dynamically resized:

class MyPanel: Panel
{

    public const int WM_GETMINMAXINFO = 0x24;

    public struct POINTAPI
    {
        public Int32 X;
        public Int32 Y;
    }

    public struct MINMAXINFO
    {
        public POINTAPI ptReserved;
        public POINTAPI ptMaxSize;
        public POINTAPI ptMaxPosition;
        public POINTAPI ptMinTrackSize;
        public POINTAPI ptMaxTrackSize;
    }

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_GETMINMAXINFO:
                MINMAXINFO mmi = (MINMAXINFO)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(MINMAXINFO));
                mmi.ptMinTrackSize.X = this.MinimumSize.Width;
                mmi.ptMinTrackSize.Y = this.MinimumSize.Height;
                System.Runtime.InteropServices.Marshal.StructureToPtr(mmi, m.LParam, true);
                break;
        }
        base.WndProc(ref m);
    }

}



回答2:


Just set the MinimumSize property:

This class here is part of one of my Nuget packages. I added this MinimumSize in the constructor just to show you, I usually don't have that in the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DataJuggler.Win.Controls.Objects
{

    #region class PanelExtender : Panel
    /// <summary>
    /// This class inherits from Panel; this is intended to stop the flickering on panels
    /// </summary>
    public class PanelExtender : Panel
    {

        #region Constructor
        /// <summary>
        /// Create a new instance of a PanelExtender object
        /// </summary>
        public PanelExtender()
        {
            // Set Style to stop flickering
            this.SetStyle(System.Windows.Forms.ControlStyles.UserPaint | System.Windows.Forms.ControlStyles.AllPaintingInWmPaint | System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer, true);

            // Set the minimum size
            this.MinimumSize = new System.Drawing.Size(400, 800);
        }
        #endregion

        #region Properties

            #region CreateParams
            /// <summary>
            /// This property here is what did the trick to reduce the flickering.
            /// I also needed to make all of the controls Double Buffered, but
            /// this was the final touch. It is a little slow when you switch tabs
            /// but that is because the repainting is finishing before control is
            /// returned.
            /// </summary>
            protected override CreateParams CreateParams
            {
                get
                {
                    // initial value
                    CreateParams cp = base.CreateParams;

                    // Apparently this interrupts Paint to finish before showing
                    cp.ExStyle |= 0x02000000;

                    // return value
                    return cp;
                }
            }
            #endregion

        #endregion

    }
    #endregion

}

I am not sure about the resizing you need, adjust to suit your situation.

In case you want it:

Nuget: DataJuggler.Win.Controls

Source: https://github.com/DataJuggler/DataJuggler.Win.Controls




回答3:


The Full Working Code: Thnks for the help

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Move_Resize_Controls
{
    class MyPanel: Panel
    {


        // For Moving Panel "Drag the Titlebar and move the panel"
        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();





        // Constructor
        public MyPanel()
        {

            typeof(MyPanel).InvokeMember("DoubleBuffered", BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, this, new object[] { true }); // Double buffer MyPanel
            TitleBar(); // TitleBar
            this.MinimumSize = new System.Drawing.Size(200, 200);
        }






        // Resize function for the panel - "Resizable Panel"
        protected override CreateParams CreateParams
        {
            get
            {
                var cp = base.CreateParams;
                cp.Style |= (int)0x00040000L;  // Turn on WS_BORDER + WS_THICKFRAME
                //cp.Style |= (int)0x00C00000L;  // Move
                return cp;

            }
        }







        // The Title Bar
        private void TitleBar()
        {
            Panel titleBar = new Panel();
            titleBar.BackColor = Color.Black;
            titleBar.Size = new Size(this.Size.Width, 20);
            titleBar.Dock = DockStyle.Top;
            this.Controls.Add(titleBar);

            titleBar.MouseDown  += new System.Windows.Forms.MouseEventHandler(this.MouseDownTitleBar); // Mouse Down - Event
            typeof(Panel).InvokeMember("DoubleBuffered", BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, titleBar, new object[] { true }); // Double Buffered 

        }








        // Move Panel
        private void MouseDownTitleBar(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }






     // Make the Minumum Size - Work
        public const int WM_GETMINMAXINFO = 0x24;

        public struct POINTAPI
        {
            public Int32 X;
            public Int32 Y;
        }


        public struct MINMAXINFO
        {
            public POINTAPI ptReserved;
            public POINTAPI ptMaxSize;
            public POINTAPI ptMaxPosition;
            public POINTAPI ptMinTrackSize;
            public POINTAPI ptMaxTrackSize;
        }


        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_GETMINMAXINFO:
                    MINMAXINFO mmi = (MINMAXINFO)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(MINMAXINFO));
                    mmi.ptMinTrackSize.X = this.MinimumSize.Width;
                    mmi.ptMinTrackSize.Y = this.MinimumSize.Height;
                    System.Runtime.InteropServices.Marshal.StructureToPtr(mmi, m.LParam, true);
                    break;
            }
            base.WndProc(ref m);
        }




    }
}


来源:https://stackoverflow.com/questions/62473008/how-to-set-minimum-size-of-custom-control-with-createparams

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!