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="Polygon 클래스 : 다각형 그리기/편집하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Window.CommandBindings>
<CommandBinding Command="New"
CanExecute="NewCommand_CanExecute"
Executed="NewCommand_Executed" />
<CommandBinding Command="Open"
CanExecute="OpenCommand_CanExecute"
Executed="OpenCommand_Executed" />
<CommandBinding Command="SaveAs"
CanExecute="SaveAsCommand_CanExecute"
Executed="SaveAsCommand_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+S" Command="SaveAs" />
</Window.InputBindings>
<DockPanel>
<Menu DockPanel.Dock="Top"
Padding="5"
FontFamily="나눔고딕코딩"
FontSize="16">
<MenuItem Header="파일(_F)">
<MenuItem Command="New" />
<MenuItem Command="Open" />
<MenuItem Command="SaveAs"
InputGestureText="Ctrl+S" />
<Separator />
<MenuItem Name="exitMenuItem"
Header="종료(_E)" />
</MenuItem>
</Menu>
<StackPanel DockPanel.Dock="Top"
Margin="10"
Orientation="Horizontal">
<RadioButton Name="drawRadioButton"
Margin="5"
IsChecked="True"
Content="그리기" />
<RadioButton Name="editRadioButton"
Margin="5"
Content="편집" />
</StackPanel>
<Border Name="border"
Margin="10"
BorderBrush="Gray"
BorderThickness="1">
<Canvas Name="canvas"
Background="Transparent"
ClipToBounds="True" />
</Border>
</DockPanel>
</Window>
728x90
▶ MainWindow.xaml.cs
using Microsoft.Win32;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Shapes;
namespace TestProject
{
/// <summary>
/// 메인 윈도우
/// </summary>
public partial class MainWindow : Window
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 신규 다각형
/// </summary>
private Polyline newPolyline = null;
/// <summary>
/// 편집 여부
/// </summary>
private bool isEditing = false;
/// <summary>
/// 편집시 다각형 히트 타입
/// </summary>
private PolygonHitType editPolygonHitType = PolygonHitType.None;
/// <summary>
/// 편집 다각형
/// </summary>
private Polygon editPolygon = null;
/// <summary>
/// 편집 다각형 파트 인덱스
/// </summary>
private int editPolygonPartIndex = -1;
/// <summary>
/// 편집 마지막 포인트
/// </summary>
private Point editLastPoint = new Point(double.NegativeInfinity, double.NegativeInfinity);
/// <summary>
/// 파일 열기 대화 상자
/// </summary>
private OpenFileDialog openFileDialog = new OpenFileDialog();
/// <summary>
/// 파일 저장 대화 상자
/// </summary>
private SaveFileDialog saveFileDialog = new SaveFileDialog();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainWindow()
/// <summary>
/// 생성자
/// </summary>
public MainWindow()
{
InitializeComponent();
this.openFileDialog.Filter = "DRW Files (*.drw)|*.drw|All files (*.*)|*.*";
this.openFileDialog.DefaultExt = "drw";
this.saveFileDialog.Filter = "DRW Files (*.drw)|*.drw|All files (*.*)|*.*";
this.saveFileDialog.DefaultExt = "drw";
this.exitMenuItem.Click += exitMenuItem_Click;
this.editRadioButton.Click += editRadioButton_Click;
this.canvas.MouseDown += canvas_MouseDown;
this.canvas.MouseMove += canvas_MouseMove;
this.canvas.MouseUp += canvas_MouseUp;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 새로 만들기 명령 실행 가능 여부 구하기 - NewCommand_CanExecute(sender, e)
/// <summary>
/// 새로 만들기 명령 실행 가능 여부 구하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void NewCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CanExecute(true);
}
#endregion
#region 새로 만들기 명령 실행시 처리하기 - NewCommand_Executed(sender, e)
/// <summary>
/// 새로 만들기 명령 실행시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
this.canvas.Children.Clear();
}
#endregion
#region 열기 명령 실행 가능 여부 구하기 - OpenCommand_CanExecute(sender, e)
/// <summary>
/// 열기 명령 실행 가능 여부 구하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void OpenCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CanExecute(false);
}
#endregion
#region 열기 명령 실행시 처리하기 - OpenCommand_Executed(sender, e)
/// <summary>
/// 열기 명령 실행시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void OpenCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
if(this.openFileDialog.ShowDialog().Value)
{
string xaml = File.ReadAllText(this.openFileDialog.FileName);
this.canvas = (Canvas)XamlReader.Parse(xaml);
this.border.Child = this.canvas;
this.canvas.MouseMove += canvas_MouseMove;
this.canvas.MouseDown += canvas_MouseDown;
this.canvas.MouseUp += canvas_MouseUp;
}
}
#endregion
#region 다른 이름으로 저장 명령 실행 가능 여부 구하기 - SaveAsCommand_CanExecute(sender, e)
/// <summary>
/// 다른 이름으로 저장 명령 실행 가능 여부 구하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void SaveAsCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CanExecute(true);
}
#endregion
#region 다른 이름으로 저장 명령 실행시 처리하기 - SaveAsCommand_Executed(sender, e)
/// <summary>
/// 다른 이름으로 저장 명령 실행시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void SaveAsCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
if(this.saveFileDialog.ShowDialog().Value)
{
string xaml = XamlWriter.Save(this.canvas);
File.WriteAllText(this.saveFileDialog.FileName, xaml);
}
}
#endregion
#region 종료 메뉴 항목 클릭시 처리하기 - exitMenuItem_Click(sender, e)
/// <summary>
/// 종료 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void exitMenuItem_Click(object sender, RoutedEventArgs e)
{
Close();
}
#endregion
#region 편집 라디오 버튼 클릭시 처리하기 - editRadioButton_Click(sender, e)
/// <summary>
/// 편집 라디오 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void editRadioButton_Click(object sender, RoutedEventArgs e)
{
FinishPolygon();
}
#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)
{
if(this.drawRadioButton.IsChecked.Value)
{
#region 그리기시
if(e.RightButton == MouseButtonState.Pressed)
{
FinishPolygon();
return;
}
Point mousePoint = e.GetPosition(this.canvas);
if(this.newPolyline == null)
{
this.newPolyline = new Polyline();
this.newPolyline.Stroke = Brushes.Red;
this.newPolyline.StrokeThickness = 1;
this.newPolyline.StrokeDashArray = new DoubleCollection();
this.newPolyline.StrokeDashArray.Add(5);
this.newPolyline.StrokeDashArray.Add(5);
this.newPolyline.Points.Add(mousePoint);
this.canvas.Children.Add(this.newPolyline);
}
this.newPolyline.Points.Add(mousePoint);
#endregion
}
else
{
#region 편집시
if(this.editPolygon == null)
{
return;
}
this.editLastPoint = e.GetPosition(canvas);
this.isEditing = true;
this.canvas.CaptureMouse();
#endregion
}
}
#endregion
#region 캔버스 마우스 이동시 처리하기 - canvas_MouseMove(sender, e)
/// <summary>
/// 캔버스 마우스 이동시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
Point mousePoint = e.GetPosition(this.canvas);
if(this.drawRadioButton.IsChecked.Value)
{
if(this.newPolyline == null)
{
return;
}
this.newPolyline.Points[this.newPolyline.Points.Count - 1] = mousePoint;
}
else
{
if(this.isEditing)
{
if(this.editPolygonHitType == PolygonHitType.Vertex)
{
MoveVertex(e);
}
else if(this.editPolygonHitType == PolygonHitType.Edge)
{
MovePolygon(e);
}
}
else
{
Cursor newCursor = null;
SetEditPolygon(mousePoint);
if(this.editPolygonHitType == PolygonHitType.Vertex)
{
newCursor = Cursors.Cross;
}
else if(this.editPolygonHitType == PolygonHitType.Edge)
{
newCursor = Cursors.SizeAll;
}
if(this.canvas.Cursor != newCursor)
{
this.canvas.Cursor = newCursor;
}
}
}
}
#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.isEditing = false;
this.canvas.ReleaseMouseCapture();
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 실행 가능 여부 구하기 - CanExecute(requirePolygon)
/// <summary>
/// 실행 가능 여부 구하기
/// </summary>
/// <param name="requirePolygon">다각형 필요 여부</param>
/// <returns>실행 가능 여부 구하기</returns>
private bool CanExecute(bool requirePolygon)
{
if(this.newPolyline != null)
{
return false;
}
if(this.editPolygon != null)
{
return false;
}
if(requirePolygon)
{
return this.canvas.Children.Count > 0;
}
return true;
}
#endregion
#region 다각형 끝내기 - FinishPolygon()
/// <summary>
/// 다각형 끝내기
/// </summary>
private void FinishPolygon()
{
if(this.newPolyline == null)
{
return;
}
if(this.newPolyline.Points.Count > 3)
{
this.newPolyline.Points.RemoveAt(this.newPolyline.Points.Count - 1);
Polygon newPolygon = new Polygon();
newPolygon.Stroke = Brushes.Blue;
newPolygon.StrokeThickness = 2;
newPolygon.Points = this.newPolyline.Points;
this.canvas.Children.Add(newPolygon);
}
this.canvas.Children.Remove(this.newPolyline);
this.newPolyline = null;
}
#endregion
#region 꼭지점 이동하기 - MoveVertex(e)
/// <summary>
/// 꼭지점 이동하기
/// </summary>
/// <param name="e">이벤트 인자</param>
private void MoveVertex(MouseEventArgs e)
{
Point mousePoint = e.GetPosition(this.canvas);
double deltaX = mousePoint.X - this.editLastPoint.X;
double deltaY = mousePoint.Y - this.editLastPoint.Y;
Point newPoint = new Point
(
this.editPolygon.Points[this.editPolygonPartIndex].X + deltaX,
this.editPolygon.Points[this.editPolygonPartIndex].Y + deltaY
);
this.editPolygon.Points[this.editPolygonPartIndex] = newPoint;
this.editLastPoint = mousePoint;
}
#endregion
#region 다각형 이동하기 - MovePolygon(e)
/// <summary>
/// 다각형 이동하기
/// </summary>
/// <param name="e">이벤트 인자</param>
private void MovePolygon(MouseEventArgs e)
{
Point mousePoint = e.GetPosition(this.canvas);
double deltaX = mousePoint.X - this.editLastPoint.X;
double deltaY = mousePoint.Y - this.editLastPoint.Y;
int pointCount = this.editPolygon.Points.Count;
for(int i = 0; i < pointCount; i++)
{
Point newPoint = new Point
(
this.editPolygon.Points[i].X + deltaX,
this.editPolygon.Points[i].Y + deltaY
);
this.editPolygon.Points[i] = newPoint;
}
this.editLastPoint = mousePoint;
}
#endregion
#region 편집 다각형 설정하기 - SetEditPolygon(point)
/// <summary>
/// 편집 다각형 설정하기
/// </summary>
/// <param name="point">포인트</param>
private void SetEditPolygon(Point point)
{
this.editPolygon = null;
this.editPolygonHitType = PolygonHitType.None;
this.editPolygonPartIndex = -1;
foreach(UIElement element in this.canvas.Children)
{
Polygon polygon = element as Polygon;
if(polygon == null)
{
continue;
}
if(polygon.IsAt(point, out this.editPolygonHitType, out this.editPolygonPartIndex))
{
this.editPolygon = polygon;
return;
}
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] AxisAngleRotation3D 엘리먼트 : 3D 애니메이션 사용하기 (0) | 2020.08.10 |
---|---|
[C#/WPF] DoubleAnimation 엘리먼트 : EasingFunction 속성에서 CircleEase 객체 사용하기 (0) | 2020.08.10 |
[C#/WPF] DoubleAnimation 엘리먼트 : EasingFunction 속성에서 BounceEase 객체 사용하기 (0) | 2020.08.09 |
[C#/WPF] ElasticEase 엘리먼트 사용하기 (0) | 2020.08.09 |
[C#/WPF] Slider 엘리먼트 사용하기 (0) | 2020.08.09 |
[C#/WPF] Keyboard 클래스 : FocusedElement 정적 속성을 사용해 포커스 엘리먼트 구하기 (0) | 2020.08.09 |
[C#/WPF] FocusManager 클래스 : GetFocusedElement 정적 메소드를 사용해 포커스 엘리먼트 구하기 (0) | 2020.08.09 |
[C#/WPF] FrameworkElement 클래스 : MoveFocus 메소드를 사용해 포커스 이동하기 (0) | 2020.08.09 |
[C#/WPF] Button 엘리먼트 : Style 속성 사용하기 (0) | 2020.08.09 |
[C#/WPF] Cursor 클래스 : 리소스 커서 로드하기 (0) | 2020.08.09 |
댓글을 달아 주세요