첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ MainWindow.xaml

<Window x:Class="TestProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="800"
    Height="600"
    Title="도형 위치/크기 변경하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Canvas Name="canvas"
        Background="Transparent">
        <Border Canvas.Left="50" Canvas.Top="30"
            Width="500"
            Height="300"
            BorderBrush="LightBlue"
            BorderThickness="5" />
        <Ellipse Canvas.Left="50" Canvas.Top="50"
            Width="200"
            Height="200"
            Stroke="Red"
            StrokeThickness="3">
            <Ellipse.Fill>
                <LinearGradientBrush
                    StartPoint="0 0"
                    EndPoint="0 1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="White" Offset="0" />
                        <GradientStop Color="Red"   Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Ellipse.Fill>
        </Ellipse>
        <Polygon Canvas.Left="50" Canvas.Top="150"
            Stroke="Green"
            StrokeThickness="3"
            Points="100 0 200 100 100 200 0 100 100 0">
            <Polygon.Fill>
                <LinearGradientBrush
                    StartPoint="0 0"
                    EndPoint="0 1">
                    <GradientStop Color="White" Offset="0" />
                    <GradientStop Color="Green" Offset="1" />
                </LinearGradientBrush>
            </Polygon.Fill>
        </Polygon>
        <Rectangle Canvas.Left="200" Canvas.Top="200"
            Width="200"
            Height="200"
            Stroke="Blue"
            StrokeThickness="3">
            <Rectangle.Fill>
                <LinearGradientBrush
                    EndPoint="0 1"
                    StartPoint="0 0">
                    <GradientStop Color="White" Offset="0" />
                    <GradientStop Color="Blue"  Offset="1" />
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Canvas>
</Window>

 

728x90

 

▶ MainWindow.xaml.cs

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public partial class MainWindow : Window
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 히트 타입 - HitType

        /// <summary>
        /// 히트 타입
        /// </summary>
        private enum HitType
        {
            /// <summary>
            /// 해당 무
            /// </summary>
            None,

            /// <summary>
            /// 몸체
            /// </summary>
            Body,

            /// <summary>
            /// 좌상단
            /// </summary>
            UpperLeft,

            /// <summary>
            /// 우상단
            /// </summary>
            UpperRight,

            /// <summary>
            /// 우하단
            /// </summary>
            LowerRight,

            /// <summary>
            /// 좌하단
            /// </summary>
            LowerLeft,

            /// <summary>
            /// 왼쪽
            /// </summary>
            Left,

            /// <summary>
            /// 오른쪽
            /// </summary>
            Right,

            /// <summary>
            /// 위쪽
            /// </summary>
            Top,

            /// <summary>
            /// 아래쪽
            /// </summary>
            Bottom
        };

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 드래그 여부
        /// </summary>
        private bool isDragging = false;

        /// <summary>
        /// 마지막 포인트
        /// </summary>
        private Point lastPoint;

        /// <summary>
        /// 히트 타입
        /// </summary>
        private HitType hitType = HitType.None;

        /// <summary>
        /// 히트 도형
        /// </summary>
        private Shape hitShape = null;

        /// <summary>
        /// 도형 리스트
        /// </summary>
        private List<Shape> shapeList;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            Loaded                += Window_Loaded;
            this.canvas.MouseDown += canvas_MouseDown;
            this.canvas.MouseMove += canvas_MouseMove;
            this.canvas.MouseUp   += canvas_MouseUp;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 윈도우 로드시 처리하기 - Window_Loaded(sender, e)

        /// <summary>
        /// 윈도우 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.shapeList = new List<Shape>();

            foreach(UIElement child in this.canvas.Children)
            {
                if(child is Shape)
                {
                    this.shapeList.Add(child as Shape);
                }
            }

            this.shapeList.Reverse();
        }

        #endregion
        #region 캔버스 마우스 DOWN 처리하기 - canvas_MouseDown(sender, e)

        /// <summary>
        /// 캔버스 마우스 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            FindHit(Mouse.GetPosition(this.canvas));

            SetMouseCursor();

            if(this.hitType == HitType.None)
            {
                return;
            }

            this.lastPoint = Mouse.GetPosition(this.canvas);

            this.isDragging = true;
        }

        #endregion
        #region 캔버스 마우스 이동시 처리하기 - canvas_MouseMove(sender, e)

        /// <summary>
        /// 캔버스 마우스 이동시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if(!this.isDragging)
            {
                FindHit(Mouse.GetPosition(this.canvas));

                SetMouseCursor();
            }
            else if(this.hitShape is Polygon)
            {
                // 다각형은 처리하지 않는다.
            }
            else
            {
                Point point = Mouse.GetPosition(this.canvas);

                double offsetX = point.X - this.lastPoint.X;
                double offsetY = point.Y - this.lastPoint.Y;

                double newX = Canvas.GetLeft(this.hitShape);
                double newY = Canvas.GetTop (this.hitShape);

                double newWidth  = this.hitShape.Width;
                double newHeight = this.hitShape.Height;

                switch(this.hitType)
                {
                    case HitType.Body :

                        newX += offsetX;
                        newY += offsetY;

                        break;

                    case HitType.UpperLeft :

                        newX += offsetX;
                        newY += offsetY;

                        newWidth  -= offsetX;
                        newHeight -= offsetY;

                        break;

                    case HitType.UpperRight :

                        newY += offsetY;

                        newWidth  += offsetX;
                        newHeight -= offsetY;

                        break;

                    case HitType.LowerRight :

                        newWidth  += offsetX;
                        newHeight += offsetY;

                        break;

                    case HitType.LowerLeft :

                        newX += offsetX;

                        newWidth  -= offsetX;
                        newHeight += offsetY;

                        break;

                    case HitType.Left :

                        newX += offsetX;

                        newWidth -= offsetX;

                        break;

                    case HitType.Right :

                        newWidth += offsetX;

                        break;

                    case HitType.Bottom :

                        newHeight += offsetY;

                        break;

                    case HitType.Top :

                        newY += offsetY;

                        newHeight -= offsetY;

                        break;
                }

                if((newWidth > 0) && (newHeight > 0))
                {
                    Canvas.SetLeft(this.hitShape, newX);
                    Canvas.SetTop (this.hitShape, newY);

                    this.hitShape.Width  = newWidth;
                    this.hitShape.Height = newHeight;

                    this.lastPoint = point;
                }
            }
        }

        #endregion
        #region 캔버스 마우스 UP 처리하기 - canvas_MouseUp(sender, e)

        /// <summary>
        /// 캔버스 마우스 UP 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.isDragging = false;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 상하좌우 설정하기 - SetLRTB(shape, left, right, top, bottom)

        /// <summary>
        /// 상하좌우 설정하기
        /// </summary>
        /// <param name="shape">도형</param>
        /// <param name="left">왼쪽</param>
        /// <param name="right">오른쪽</param>
        /// <param name="top">위쪽</param>
        /// <param name="bottom">아래쪽</param>
        private void SetLRTB(Shape shape, out double left, out double right, out double top, out double bottom)
        {
            if(!(shape is Polygon))
            {
                left   = Canvas.GetLeft(shape);
                top    = Canvas.GetTop(shape);
                right  = left + shape.ActualWidth;
                bottom = top  + shape.ActualHeight;

                return;
            }

            Polygon polygon = shape as Polygon;

            left   = polygon.Points[0].X;
            right  = left;
            top    = polygon.Points[0].Y;
            bottom = top;

            foreach(Point point in polygon.Points)
            {
                if(left > point.X)
                {
                    left = point.X;
                }

                if(right < point.X)
                {
                    right = point.X;
                }

                if(top > point.Y)
                {
                    top = point.Y;
                }

                if(bottom < point.Y)
                {
                    bottom = point.Y;
                }
            }

            left   += Canvas.GetLeft(shape);
            right  += Canvas.GetLeft(shape);
            top    += Canvas.GetTop (shape);
            bottom += Canvas.GetTop (shape);
        }

        #endregion
        #region 히트 타입 구하기 - GetHitType(shape, point)

        /// <summary>
        /// 히트 타입 구하기
        /// </summary>
        /// <param name="shape">도형</param>
        /// <param name="point">포인트</param>
        /// <returns>히트 타입</returns>
        private HitType GetHitType(Shape shape, Point point)
        {
            double left;
            double right;
            double top;
            double bottom;

            SetLRTB(shape, out left, out right, out top, out bottom);

            if(point.X < left  ) return HitType.None;
            if(point.X > right ) return HitType.None;
            if(point.Y < top   ) return HitType.None;
            if(point.Y > bottom) return HitType.None;

            const double GAP = 10;

            if(point.X - left < GAP)
            {
                if(point.Y - top < GAP)
                {
                    return HitType.UpperLeft;
                }

                if(bottom - point.Y < GAP)
                {
                    return HitType.LowerLeft;
                }

                return HitType.Left;
            }

            if(right - point.X < GAP)
            {
                if(point.Y - top < GAP)
                {
                    return HitType.UpperRight;
                }

                if(bottom - point.Y < GAP)
                {
                    return HitType.LowerRight;
                }

                return HitType.Right;
            }

            if(point.Y - top < GAP)
            {
                return HitType.Top;
            }

            if(bottom - point.Y < GAP)
            {
                return HitType.Bottom;
            }

            return HitType.Body;
        }

        #endregion
        #region 히트 찾기 - FindHit(point)

        /// <summary>
        /// 히트 찾기
        /// </summary>
        /// <param name="point">포인트</param>
        private void FindHit(Point point)
        {
            this.hitShape = null;
            this.hitType  = HitType.None;

            foreach(Shape shape in this.shapeList)
            {
                this.hitType = GetHitType(shape, point);

                if(this.hitType != HitType.None)
                {
                    this.hitShape = shape;

                    return;
                }
            }

            return;
        }

        #endregion
        #region 마우스 커서 설정하기 - SetMouseCursor()

        /// <summary>
        /// 마우스 커서 설정하기
        /// </summary>
        private void SetMouseCursor()
        {
            Cursor cursor = Cursors.Arrow;

            switch(this.hitType)
            {
                case HitType.None       : cursor = Cursors.Arrow;     break;
                case HitType.Body       : cursor = Cursors.ScrollAll; break;
                case HitType.UpperLeft  :
                case HitType.LowerRight : cursor = Cursors.SizeNWSE;  break;
                case HitType.LowerLeft  :
                case HitType.UpperRight : cursor = Cursors.SizeNESW;  break;
                case HitType.Top        :
                case HitType.Bottom     : cursor = Cursors.SizeNS;    break;
                case HitType.Left       :
                case HitType.Right      : cursor = Cursors.SizeWE;    break;
            }

            if(Cursor != cursor)
            {
                Cursor = cursor;
            }
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요