Feedback

C# - Verschiebbares und Größenverstellbares Control

Veröffentlicht von am 2/15/2014
(0 Bewertungen)
Mit dieser Klasse (MoveControl) kann man Controls erzeugen, welche sich zur Laufzeit verschieben lassen.
Hier die neuste Version.
Die alte gibt es unter:
https://www.dropbox.com/s/iowrmvx7ldlnjel/v1-2014-02-16-description.txt
und:
https://www.dropbox.com/s/736o5c00zuhnqmf/v1-2014-02-16-code.cs

Um das Control zu nutzen, einfach ein neues Control oder eine neue Klasse erstellen und die obere Klasse (MoveControl) hinein Kopieren.
Auch wenn die Klasse folgend von Button erbt, ist bei den Klasseninternen Namen immer Control zu finden, damit das "Button" einfach gegen ein Beliebiges anderes Control augetauscht werden kann.

Das Control unterscheidet sich neben der einfachen Verschiebe- und Vergrößer- bzw. Verkleinerungsmöglichkeit durch seine weiteren Eigenschaften:
Ich denke diese sind in der Summary recht gut beschrieben, weswegen ich mir das jetzt spare. Nur grob:
In der Designerabteilung Grid hat man die Möglichkeit ein Raster auf das Formular zeichnen zu lassen bzw. als Hintergrundbild zu setzen. Dafür muss man die Eigenschaft auf Show auf Draw(->wird gezeichnet) oder Show (-> Wird als Hintergrundbild angezeigt). Einige Eigenschaften beziehen sich dann jeweils auf nur eine dieser beiden Optionen. Wenn man eine Eigenschaft fehlerhafterweise setzt, passiert aber nichts schlimmes sondern die entsprechende Option tritt einfach nicht in Kraft. Also nicht wundern, sondern Summary lesen. Und wenn dort nichts steht einfach fragen. :)
Zu Beachten ist, dass man, um das Grid benutzen zu können im Form Load moveControlX.EnableGrid(this); aufrufen muss.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Drawing2D;

namespace DariusArnold
{
    public partial class MoveControl : Button
    {
        /// <summary>
        /// Neue Instanz des bewegbaren Benutzersteuerelements.
        /// </summary>
        public MoveControl()
        {
            CanMove = true;
            CanResize = true;
            SnapsToGrid = true;
            SizesToGrid = true;
            ChangeCursor = true;
            Grid = GridMode.ShowWhileMoving;
            ViewGrid = GridViewingTypes.Draw;
            CustomGridPixel = new bool[]{ false,
                                false,
                                false,
                                  true,
                                  true,
                                  true,
                                  true,
                                  true,
                                false,
                                false };
            GridColor = SystemColors.ControlDarkDark;
            GridLineWidth = 2f;
            GridDashStyle = DashStyle.Dot;
            ResizeCornerSize = new Size(5, 5);
            MinimumSize = new Size(20, 20);
            AutoSize = false;
            MarkResizeCorner = true;
            ShowValueBoxes = true;
            ResizeCornerMarkingColor = Color.Blue;
            DoubleBuffered = true;

            this.MouseDown += new MouseEventHandler(c_MouseDown);
            this.MouseUp += new MouseEventHandler(c_MouseUp);
            this.MouseMove += new MouseEventHandler(c_MouseMove);
            this.Paint += new PaintEventHandler(c_Paint);
        }

        private int x, y;
        private bool move, resize;
        private Rectangle oControl = new Rectangle();
        private Form form = null;
        private GridMode gm = GridMode.ShowNever;

        /// <summary>
        /// Sets, if control can be moved during runtime.
        /// </summary>
        [CategoryAttribute("MoveAndResize"), DescriptionAttribute("Gibt an, ob das Element zur Laufzeit verschoben werden kann."), DefaultValue(true)]
        public bool CanMove { get; set; }

        /// <summary>
        /// Sets, if control can be resized during runtime.
        /// </summary>
        [CategoryAttribute("MoveAndResize"), DescriptionAttribute("Gibt an, ob die Größe des Elements zur Laufzeit verändert werden kann."), DefaultValue(true)]
        public bool CanResize { get; set; }

        /// <summary>
        /// Sets, if the control snaps to a 10x10 px grid automaticly.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Gibt an, ob sich das Element automatisch an einem 10x10-Raster ausrichten soll."), DefaultValue(true)]
        public bool SnapsToGrid { get; set; }

        /// <summary>
        /// Sets, if the control's size is adapted to a 10x10 px grid automaticly.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Gibt an, ob die Größße des Elements automatisch an ein 10x10-Raster angepasst werden soll."), DefaultValue(true)]
        public bool SizesToGrid { get; set; }

        /// <summary>
        /// Sets whether the cursor is changed if user moves the control or is able to resize it.
        /// </summary>
        [CategoryAttribute("Darstellung"), DescriptionAttribute("Gibt an, ob sich der Cursor ändern soll, wenn das Element verschoben wird oder seine Größe verändert werden kann."), DefaultValue(true)]
        public bool ChangeCursor { get; set; }

        /// <summary>
        /// Sets, if the area to drag for resize the control is colored.
        /// </summary>
        [CategoryAttribute("Darstellung"), DescriptionAttribute("Gibt an, ob der \"Angriffspunkt\" zur Größenänderung farbig hinterlegt werden soll."), DefaultValue(true)]
        public bool MarkResizeCorner { get; set; }

        /// <summary>
        /// Sets the color of the 10x10 px grid.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Gibt an, in welcher Farbe das Raster gezeichnet werden soll. (Wenn Grid auf ShowAlways oder ShowWhileMoving steht)")]
        public Color GridColor { get; set; }

        /// <summary>
        /// Sets the dash style of the 10x10 px grid.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Gibt an, in welcher Punktierungsweise das Raster gezeichnet werden soll. (Wenn Grid auf ShowAlways oder ShowWhileMoving steht)")]
        public DashStyle GridDashStyle { get; set; }

        /// <summary>
        /// Sets the width of the grid lines.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Breite der Linien des Grid")]
        public float GridLineWidth { get; set; }

        /// <summary>
        /// Sets the size of the resize area.
        /// </summary>
        [CategoryAttribute("Darstellung"), DescriptionAttribute("Gibt die Größe des \"Angriffspunktes\" zur Größenänderung an.")]
        public Size ResizeCornerSize { get; set; }

        /// <summary>
        /// Sets the color of the resize area (if MarkResizeCorner is true).
        /// </summary>
        [CategoryAttribute("Darstellung"), DescriptionAttribute("Gibt die Farbe der Markierung des\"Angriffspunktes\" zur Größenänderung an. (Wenn MarkResizeCorner auf true steht)")]
        public Color ResizeCornerMarkingColor { get; set; }

        /// <summary>
        /// Sets, if there are shown little boxes containing size or location while move or resize process.
        /// </summary>
        [CategoryAttribute("Darstellung"), DescriptionAttribute("Gibt an, ob beim Ändern der Größe oder der Position kleine Kästchen mit den entsprechenden Werten angezeigt werden."), DefaultValue(true)]
        public bool ShowValueBoxes { get; set; }

        /// <summary>
        /// Sets a custom dash style for the grid (only if ShowGrid is Show). It has to contain at least 10 values (if there are more, they won't be used). true says the pixel is colored. false says it isn't.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Gibt das Linien-Museter für das Raster der BGImage-Property an. Ein Wert entspricht einem Pixel. true = Linie; false = Lücke")]
        public bool[] CustomGridPixel { get; set; }

        public enum GridViewingTypes { Draw, Show }

        /// <summary>
        /// Sets the type of viewing the grid. Type 1 (Draw) is drawing it on the form. Type 2 (Show) is showing it as the form's background image.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Gibt an, ob das Raster gezeichnet oder über die Background-Image-Property dargestellt werden soll. Bei letzterem wird die Verwendung eines BackgroundImages unmöglich.")]
        public GridViewingTypes ViewGrid { get; set; }

        public enum GridMode { ShowAlways, ShowNever, ShowWhileMoving }

        /// <summary>
        /// Sets, when the grid is shown.
        /// </summary>
        [CategoryAttribute("Grid"), DescriptionAttribute("Gibt an, ob das Raster nie, immer oder nur beim Verschieben oder Ändern der Größe angezeigt wird."), DefaultValue(GridMode.ShowNever)]
        public GridMode Grid
        {
            get
            {
                return gm;
            }
            set
            {
                gm = value;
                try { form.Refresh(); } catch { }
            }
        }

        /// <summary>
        /// Enable grid functionality for control. Also make the size value box appear next to the cursor instead of above the control.
        /// </summary>
        /// <param name="f">The form the things (grid and value size value box) should be shown on.</param>
        public void EnableGrid(Form f)
        {
            form = f;
            if (ViewGrid == GridViewingTypes.Show)
                f.BackgroundImage = null;
            f.Paint += new PaintEventHandler(form_Paint);
            SetDoubleBuffered(f);
            if (SnapsToGrid)
                SnapToGrid();
            if (SizesToGrid)
                SizeToGrid();
            try
            {
                form.Refresh();
            }
            catch
            {
            }
        }

        /// <summary>
        /// Snap the control to the 10x10 px grid.
        /// </summary>
        public void SnapToGrid()
        {
            this.Left = (int)Math.Round((decimal)this.Left / 10, 0) * 10;
            this.Top = (int)Math.Round((decimal)this.Top / 10, 0) * 10;
        }

        /// <summary>
        /// Adapt the control's size to the 10x10 px grid.
        /// </summary>
        public void SizeToGrid()
        {
            this.Width = ((int)Math.Round((decimal)this.Width / 10, 0) * 10) + (((int)Math.Round((decimal)this.Left / 10, 0) * 10) - this.Left);
            this.Height = ((int)Math.Round((decimal)this.Height / 10, 0) * 10) + (((int)Math.Round((decimal)this.Top / 10, 0) * 10) - this.Top);
        }

        public new event EventHandler Click;

        protected virtual void OnMCClick(EventArgs e)
        {
            EventHandler eh = Click;
            if (eh != null)
            {
                eh(this, e);
            }
        }

        private void form_Paint(object sender, PaintEventArgs e)
        {
            switch (Grid)
            {
                case GridMode.ShowAlways:
                    ShowGrid(e);
                    break;
                case GridMode.ShowWhileMoving:
                    if (move | resize)
                        ShowGrid(e);
                    else
                        HideGrid();
                    break;
                case GridMode.ShowNever:
                    HideGrid();
                    break;
            }
            if (resize & ShowValueBoxes)
            {
                Point mouse = PointToClient(MousePosition);
                Point draw = mouse;
                draw.Offset(this.Location);
                draw.Offset(10, 10);
                DrawStringBox("X: " + (Math.Round((decimal)mouse.X / 10, 0) * 10).ToString() + "; Y: " + (Math.Round((decimal)mouse.Y / 10, 0) * 10).ToString(), Font, Color.Black, Color.White, SystemColors.ControlDarkDark, 1, 10, draw, e.Graphics);
            }
        }

        private void c_MouseMove(object sender, MouseEventArgs e)
        {
            if (move)
            {
                if (Grid != GridMode.ShowAlways)
                    try { form.Refresh(); } catch { }
                Point p = new Point();
                p.X = e.X + this.Left;
                p.Y = e.Y + this.Top;
                this.Left = p.X - x;
                this.Top = p.Y - y;

                Point mouse = this.Location;
                mouse.Offset(e.Location);
            }
            else if (resize)
            {
                SetBottomRightPt(this, new Point(this.Left + e.X, this.Top + e.Y));
                if (Grid != GridMode.ShowAlways)
                    try { form.Refresh(); } catch { }
            }
            else
            {
                if (((e.X > (this.Width - ResizeCornerSize.Width)) & (e.Y > (this.Height - ResizeCornerSize.Height))) & CanResize & ChangeCursor)
                    this.Cursor = Cursors.SizeNWSE;
                else
                    this.Cursor = Cursors.Default;
            }
        }

        private void c_MouseUp(object sender, MouseEventArgs e)
        {
            move = false;
            resize = false;
            if (SnapsToGrid)
                SnapToGrid();
            if (SizesToGrid)
                SizeToGrid();
            if (this.Bounds == oControl)
            {
                OnMCClick(EventArgs.Empty);
            }
            this.Cursor = Cursors.Default;
            if (Grid != GridMode.ShowAlways)
                try { form.Refresh(); } catch { }
        }

        private void c_MouseDown(object sender, MouseEventArgs e)
        {
            this.BringToFront();
            oControl = this.Bounds;
            if (((e.X > (this.Width - ResizeCornerSize.Width)) & (e.Y > (this.Height - ResizeCornerSize.Height))) & CanResize)
            {
                resize = true;
            }
            else if (CanMove)
            {
                if (ChangeCursor)
                    this.Cursor = Cursors.SizeAll;
                x = e.X;
                y = e.Y;
                move = true;
            }
        }

        private void SetBottomRightPt(Control c, Point p)
        {
            c.Width = (p.X - c.Left);
            c.Height = (p.Y - c.Top);
        }

        private void c_Paint(object sender, PaintEventArgs e)
        {
            if (MarkResizeCorner & CanResize)
                e.Graphics.FillRectangle(new SolidBrush(ResizeCornerMarkingColor), new Rectangle(new Point(Width - ResizeCornerSize.Width, Height - ResizeCornerSize.Height), ResizeCornerSize));

            if (resize & form == null & ShowValueBoxes)
                DrawStringBox("X: " + (Math.Round((decimal)Width / 10, 0) * 10).ToString() + "; Y: " + (Math.Round((decimal)Height / 10, 0) * 10).ToString(), Font, Color.Black, Color.White, SystemColors.ControlDarkDark, 1, 10, new Point(5, 5), e.Graphics);
            else if (move & ShowValueBoxes)
                DrawStringBox("X: " + (Math.Round((decimal)Left / 10, 0) * 10).ToString() + "; Y: " + (Math.Round((decimal)Right / 10, 0) * 10).ToString(), Font, Color.Black, Color.White, SystemColors.ControlDarkDark, 1, 10, new Point(5, 5), e.Graphics);
        }

        /// <summary>
        /// Show the grid. If ViewGrid is on 'Draw' it, will disapear when form is redrawn.
        /// </summary>
        /// <param name="e">The PaintEventArgs. Can be null, if ViewGrid is on 'Show'.</param>
        public void ShowGrid(PaintEventArgs e)
        {
            if (ViewGrid == GridViewingTypes.Draw)
                DrawGrid(form, GridColor, GridDashStyle, GridLineWidth, e);
            else
                ShowGrid(form, GridColor, CustomGridPixel);
        }

        /// <summary>
        /// Hide the grid. Works only if ShowGrid is on 'Show'.
        /// </summary>
        public void HideGrid()
        {
            if (ViewGrid == GridViewingTypes.Show & Grid != GridMode.ShowAlways)
                HideGrid(form);
        }

        private void SetDoubleBuffered(System.Windows.Forms.Control c)
        {
            if (System.Windows.Forms.SystemInformation.TerminalServerSession)
                return;

            System.Reflection.PropertyInfo aProp =
                  typeof(System.Windows.Forms.Control).GetProperty(
                        "DoubleBuffered",
                        System.Reflection.BindingFlags.NonPublic |
                        System.Reflection.BindingFlags.Instance);

            aProp.SetValue(c, true, null);
        }

        private void DrawStringBox(string sText, Font fText, Color cText, Color cBox, Color cBorder, int iOuterBorderWidth, int iInnerBorderWidth, Point pLocation, Graphics g)
        {
            Point pBorder = pLocation;
            Point pBox = pLocation;
            Point pText = pLocation;

            pBox.Offset(iOuterBorderWidth, iOuterBorderWidth);
            pText.Offset(iOuterBorderWidth + iInnerBorderWidth, iOuterBorderWidth + iInnerBorderWidth);

            Size szText = TextRenderer.MeasureText(sText, fText);
            Size szBox = szText;
            Size szBorder = szText;

            szBox.Width += (2 * iInnerBorderWidth);
            szBox.Height += (2 * iInnerBorderWidth);

            szBorder.Width += (2 * iInnerBorderWidth) + (2 * iOuterBorderWidth);
            szBorder.Height += (2 * iInnerBorderWidth) + (2 * iOuterBorderWidth);

            g.FillRectangle(new SolidBrush(cBorder), new Rectangle(pBorder, szBorder));
            g.FillRectangle(new SolidBrush(cBox), new Rectangle(pBox, szBox));
            g.DrawString(sText, fText, new SolidBrush(cText), pText);
        }

        private static void ShowGrid(Form f, Color c, bool[] Px)
        {
            ShowGrid(f, c, Px, false);
        }
        private static void ShowGrid(Form f, Color c, bool[] Px, bool invert)
        {
            try
            {
                if (f.BackgroundImage == null)
                {
                    if (invert)
                        Px = Px.invert();
                    Bitmap b = new Bitmap(10, 10);
                    for (int i = 0; i < 10; i++)
                    {
                        if (Px[i])
                            b.SetPixel(i, 0, c);
                    }
                    for (int i = 1; i < 10; i++)
                    {
                        if (Px[i])
                            b.SetPixel(0, i, c);
                    }
                    f.BackgroundImageLayout = ImageLayout.Tile;
                    f.BackgroundImage = b;
                    if (invert)
                        Px = Px.invert();
                }
            }
            catch
            {
            }
        }

        private static void HideGrid(Form f)
        {
            try
            {
                f.BackgroundImage = null;
            }
            catch
            {
            }
        }

        private static Grid g;
        public static void DrawGrid(Form f, Color c, DashStyle d, float penWidth, PaintEventArgs e)
        {
            g = new Grid();
            g.HorizontalCells = f.Height / 10 + 1;
            g.VerticalCells = f.Width / 10 + 1;
            Pen myPen = new Pen(c, penWidth);
            myPen.DashStyle = d;
            myPen.DashCap = DashCap.Triangle;
            g.Draw(e.Graphics, myPen);
        }
    }

    public static class Ext
    {
        public static bool[] invert(this bool[] input)
        {
            for (int i = 0; i < input.Length; i++)
                input[i] = !input[i];
            return input;
        }
    }

    public class Grid
    {
        public Grid()
        {
            Origin = new Point(0, 0);
            GridCellSize = new Size(10, 10);
            HorizontalCells = 1;
            VerticalCells = 1;
        }
        public int HorizontalCells { get; set; }
        public int VerticalCells { get; set; }
        public Point Origin { get; set; }
        public Size GridCellSize { get; set; }
        public virtual void Draw(Graphics Graf, Pen pencil)
        {
            Point startP = new Point();
            Point endP = new Point();
            // Draw horizontals
            startP.X = Origin.X;
            endP.X = Origin.X + VerticalCells * GridCellSize.Width;
            for (int i = 0; i <= HorizontalCells; i++)
            {
                startP.Y = Origin.Y + i * GridCellSize.Height;
                endP.Y = startP.Y;
                Graf.DrawLine(pencil, startP, endP);
            }
            // Draw verticals
            startP.Y = Origin.Y;
            endP.Y = Origin.Y + HorizontalCells * GridCellSize.Height;
            for (int i = 0; i <= VerticalCells; i++)
            {
                startP.X = Origin.X + i * GridCellSize.Width;
                endP.X = startP.X;
                Graf.DrawLine(pencil, startP, endP);
            }
        }
    }
}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!