728x90
반응형
728x170
▶ 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"
Stroke="Red"
StrokeThickness="3"
Width="200"
Height="200">
<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
Stroke="Green"
StrokeThickness="3"
Points="150 150 250 250 150 350 50 250 150 150">
<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="250"
Width="200"
Height="200"
Stroke="Blue"
StrokeThickness="3">
<Rectangle.Fill>
<LinearGradientBrush
StartPoint="0 0"
EndPoint="0 1">
<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.Media;
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 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
{
ResizeShape();
}
}
#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;
}
}
}
#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
#region 다각형 업데이트하기 - UpdatePolygon(left, right, top, bottom, newX, newY, newWidth, newHeight)
/// <summary>
/// 다각형 업데이트하기
/// </summary>
/// <param name="left">왼쪽</param>
/// <param name="right">오른쪽</param>
/// <param name="top">위쪽</param>
/// <param name="bottom">아래쪽</param>
/// <param name="newX">신규 X</param>
/// <param name="newY">신규 Y</param>
/// <param name="newWidth">신규 너비</param>
/// <param name="newHeight">신규 높이</param>
private void UpdatePolygon
(
double left,
double right,
double top,
double bottom,
double newX,
double newY,
double newWidth,
double newHeight
)
{
double scaleX = newWidth / (right - left);
double scaleY = newHeight / (bottom - top );
Polygon polygon = this.hitShape as Polygon;
List<Point> newPointList = new List<Point>();
foreach(Point point in polygon.Points)
{
double x = newX + scaleX * (point.X - left);
double y = newY + scaleY * (point.Y - top );
newPointList.Add(new Point(x, y));
}
polygon.Points = new PointCollection(newPointList);
}
#endregion
#region 도형 크기 변경하기 - ResizeShape()
/// <summary>
/// 도형 크기 변경하기
/// </summary>
private void ResizeShape()
{
Point point = Mouse.GetPosition(this.canvas);
double offsetX = point.X - this.lastPoint.X;
double offsetY = point.Y - this.lastPoint.Y;
double left;
double right;
double top;
double bottom;
SetLRTB(this.hitShape, out left, out right, out top, out bottom);
double newX = left;
double newY = top;
double newWidth = right - left;
double newHeight = bottom - top;
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))
{
return;
}
if(this.hitShape is Polygon)
{
UpdatePolygon(left, right, top, bottom, newX, newY, newWidth, newHeight);
}
else
{
Canvas.SetLeft(this.hitShape, newX);
Canvas.SetTop (this.hitShape, newY);
this.hitShape.Width = newWidth;
this.hitShape.Height = newHeight;
}
this.lastPoint = point;
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] DoubleAnimation 엘리먼트 : EasingFunction 속성에서 BackEase 객체 사용하기 (0) | 2020.08.05 |
---|---|
[C#/WPF] ScrollBar 엘리먼트 : 색상 스크롤하기 (0) | 2020.08.04 |
[C#/WPF] o:Freeze 속성 : Freezable 엘리먼트의 IsFrozen 속성 상태를 true로 설정하기 (0) | 2020.08.04 |
[C#/WPF] GridSplitter 엘리먼트 사용하기 (0) | 2020.08.04 |
[C#/WPF] Grid 엘리먼트 : ShowGridLines 속성 사용하기 (0) | 2020.08.04 |
[C#/WPF] 도형 위치/크기 변경하기 (Polygon 제외) (0) | 2020.08.04 |
[C#/WPF] DockPanel 클래스 : LastChildFill 속성 사용하기 (0) | 2020.08.04 |
[C#/WPF] Window 클래스 : WindowStyle 속성 사용하기 (0) | 2020.08.04 |
[C#/WPF] Window 클래스 : ResizeMode 속성 사용하기 (0) | 2020.08.04 |
[C#/WPF] Image 엘리먼트 : Stretch 속성 사용하기 (0) | 2020.08.03 |
댓글을 달아 주세요