Click here to Skip to main content
15,896,726 members
Articles / Desktop Programming / WPF

WPF Draggable Label

Rate me:
Please Sign up or sign in to vote.
4.63/5 (16 votes)
13 Apr 2010CPOL3 min read 62.9K   6.3K   43  
WPF label control that can be dragged and resized at runtime
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace RtwControls
{
    #region Event Handlers

    public delegate void DraggableLabelDragHandler(object sender, DraggableLabelDragEventArgs e);
    public delegate void DraggableLabelResizeHandler(object sender, DraggableLabelResizeEventArgs e);

    #endregion

    /// <summary>
    /// Label control which can be dragged and resized at runtime
    /// </summary>
    public class DraggableLabel : Label
    {
        #region Events

        public event DraggableLabelDragHandler Drag;
        public event DraggableLabelResizeHandler Resize;

        #endregion

        #region Member Variables

        private Point _previousLocation;
        private Transform _previousTransform;

        #endregion

        #region Constructors

        /// <summary>
        /// Static constructor
        /// </summary>
        static DraggableLabel()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DraggableLabel), new FrameworkPropertyMetadata(typeof(Label)));
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        public DraggableLabel()
        {
        }

        #endregion

        #region Methods

        protected void OnDrag(DraggableLabelDragEventArgs e)
        {
            DraggableLabelDragHandler handler = Drag;
            if (handler != null) handler(this, e);
        }

        protected void OnResize(DraggableLabelResizeEventArgs e)
        {
            DraggableLabelResizeHandler handler = Resize;
            if (handler != null) handler(this, e);
        }

        #endregion

        #region Overrides

        protected override void OnMouseEnter(MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                this.CaptureMouse();
            }

            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            this.ReleaseMouseCapture();
            base.OnMouseLeave(e);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            this.ReleaseMouseCapture();
            base.OnMouseLeftButtonUp(e);
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            this.CaptureMouse();
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            Window wnd = Window.GetWindow(this);
            Point currentLocation = e.MouseDevice.GetPosition(wnd);

            var move = new TranslateTransform(
                    currentLocation.X - _previousLocation.X, currentLocation.Y - _previousLocation.Y);

            double width = double.IsNaN(this.Width) ? this.ActualWidth : this.Width;
            double height = double.IsNaN(this.Height) ? this.ActualHeight : this.Height;

            if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (this.Cursor == Cursors.Hand)
                {
                    var group = new TransformGroup();
                    if (_previousTransform != null)
                    {
                        group.Children.Add(_previousTransform);
                    }
                    group.Children.Add(move);

                    this.RenderTransform = group;

                    // Invoke drag event
                    OnDrag(new DraggableLabelDragEventArgs(currentLocation));
                }
                else if (this.Cursor == Cursors.SizeWE)
                {
                    if (width + currentLocation.X - _previousLocation.X > this.MinWidth)
                    {
                        this.Width = width + currentLocation.X - _previousLocation.X;
                    }

                    // Invoke resize event
                    OnResize(new DraggableLabelResizeEventArgs(new Size(this.Width, this.Height)));
                }
                else if (this.Cursor == Cursors.SizeNS)
                {
                    if (height + currentLocation.Y - _previousLocation.Y > this.MinHeight)
                    {
                        this.Height = height + currentLocation.Y - _previousLocation.Y;
                    }

                    // Invoke resize event
                    OnResize(new DraggableLabelResizeEventArgs(new Size(this.Width, this.Height)));
                }
            }
            else
            {
                const int dragHandleWidth = 3;

                var bottomHandle = new Rect(0, height - dragHandleWidth, width, dragHandleWidth);
                var rightHandle = new Rect(width - dragHandleWidth, 0, dragHandleWidth, height);

                Point relativeLocation = wnd.TranslatePoint(currentLocation, this);

                if (rightHandle.Contains(relativeLocation))
                {
                    this.Cursor = Cursors.SizeWE;
                }
                else if (bottomHandle.Contains(relativeLocation))
                {
                    this.Cursor = Cursors.SizeNS;
                }
                else
                {
                    this.Cursor = Cursors.Hand;
                }
            }

            _previousLocation = currentLocation;
            _previousTransform = this.RenderTransform;

            base.OnMouseMove(e);
        }

        public override string ToString()
        {
            string details = string.Empty;

            double width = this.Width == double.NaN ? this.ActualWidth : this.Width;
            double height = this.Height == double.NaN ? this.ActualHeight : this.Height;

            if (this.Cursor == Cursors.Hand)
            {
                Window wnd = Window.GetWindow(this);
                Point location = this.TranslatePoint(new Point(0, 0), wnd);

                details = " : X = " + location.X + ", Y = " + location.Y;
            }
            else if (this.Cursor == Cursors.SizeWE)
            {
                details = " : Width2 = " + width;
            }
            else if (this.Cursor == Cursors.SizeNS)
            {
                details = " : Height2 = " + height;
            }

            return this.Name + details;
        }

        #endregion
    }

    #region Event Arguments

    /// <summary>
    /// Event arguments to be passed into the drag event.
    /// </summary>
    public class DraggableLabelDragEventArgs : EventArgs
    {
        private Point _location;

        public DraggableLabelDragEventArgs(Point location)
        {
            _location = location;
        }

        public int X
        {
            get
            {
                return (int)_location.X;
            }
        }

        public int Y
        {
            get
            {
                return (int)_location.Y;
            }
        }
    }

    /// <summary>
    /// Event arguments to be passed into the resize event.
    /// </summary>
    public class DraggableLabelResizeEventArgs : EventArgs
    {
        private Size _size;

        public DraggableLabelResizeEventArgs(Size size)
        {
            _size = size;
        }

        public int Width
        {
            get
            {
                return (int)_size.Width;
            }
        }

        public int Height
        {
            get
            {
                return (int)_size.Height;
            }
        }
    }

    #endregion
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions