<Window x:Class="WpfApplication21.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Interactive 2D Drawing" Height="400" Width="400">
<Window.Resources>
<SolidColorBrush x:Key="MyGrayGridBrush" Color="YellowGreen"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToolBarTray Grid.Row="0">
<ToolBar>
<RadioButton x:Name="rbSquare"
IsChecked="True" ToolTip="Add Square">
<Rectangle Width="15" Height="15"
Stroke="Blue" Fill="LightBlue"/>
</RadioButton>
<RadioButton x:Name="rbRectangle"
IsChecked="False" ToolTip="Add Rectangle">
<Rectangle Width="20" Height="12"
Stroke="Blue" Fill="LightBlue"/>
</RadioButton>
<RadioButton x:Name="rbCircle"
IsChecked="False" ToolTip="Add Circle">
<Ellipse Width="18" Height="18"
Stroke="Blue" Fill="LightBlue"/>
</RadioButton>
<RadioButton x:Name="rbEllipse"
IsChecked="False" ToolTip="Add Ellipse">
<Ellipse Width="22" Height="15"
Stroke="Blue" Fill="LightBlue"/>
</RadioButton>
<RadioButton x:Name="rbCombine"
IsChecked="False" ToolTip="Combine shapes">
<Path Fill="LightBlue" Stroke="Blue">
<Path.Data>
<CombinedGeometry>
<CombinedGeometry.Geometry1>
<EllipseGeometry
RadiusX="8"
RadiusY="8"
Center="8,8"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry
RadiusX="8"
RadiusY="8"
Center="20,8"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</RadioButton>
<RadioButton x:Name="rbSelect"
IsChecked="False" ToolTip="Select/Move">
<Polygon
Points="6 1,10 1,10 10,14 10,8 16,2 10,6 10"
Fill="LightBlue" Stroke="Blue">
<Polygon.RenderTransform>
<RotateTransform CenterX="8"
CenterY="8"
Angle="225"/>
</Polygon.RenderTransform>
</Polygon>
</RadioButton>
<RadioButton x:Name="rbDelete"
IsChecked="False" ToolTip="Delete">
<Grid>
<Line X1="2" Y1="2" X2="14"
Y2="14" Stroke="Blue"/>
<Line X1="2" Y1="14" X2="14"
Y2="2" Stroke="Blue"/>
</Grid>
</RadioButton>
</ToolBar>
</ToolBarTray>
<Viewbox Stretch="Uniform" Grid.Row="1">
<Border Margin="5" BorderBrush="Black"
BorderThickness="1" Grid.Row="1"
HorizontalAlignment="Left">
<Canvas Name="canvas1" Width="400"
Height="345" ClipToBounds="True"
Background="{StaticResource MyGrayGridBrush}"
MouseLeftButtonDown="OnMouseLeftButtonDown"
MouseLeftButtonUp="OnMouseLeftButtonUp"
MouseMove="OnMouseMove"/>
</Border>
</Viewbox>
</Grid>
</Window>
public partial class MainWindow : Window
{
private List<Path> paths = new List<Path>();
private Point startPoint = new Point();
private Shape rubberBand = null;
Point currentPoint = new Point();
private bool isDragging = false;
private bool isDown = false;
private Path originalElement = new Path();
private Path movingElement = new Path();
private Path path1 = new Path();
private Path path2 = new Path();
private SolidColorBrush fillColor =
new SolidColorBrush();
private SolidColorBrush borderColor =
new SolidColorBrush();
private SolidColorBrush selectFillColor =
new SolidColorBrush();
private SolidColorBrush selectBorderColor =
new SolidColorBrush();
public MainWindow()
{
InitializeComponent();
fillColor.Color = Colors.LightGray;
fillColor.Opacity = 0.5;
borderColor.Color = Colors.Gray;
selectFillColor.Color = Colors.LightCoral;
selectFillColor.Opacity = 0.5;
selectBorderColor.Color = Colors.Red;
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!canvas1.IsMouseCaptured)
{
startPoint = e.GetPosition(canvas1);
canvas1.CaptureMouse();
if (rbCombine.IsChecked == true)
{
SetCombineShapes(e);
}
else if (rbSelect.IsChecked == true)
{
if (canvas1 == e.Source)
return;
isDown = true;
originalElement = (Path)e.Source;
e.Handled = true;
}
else if (rbDelete.IsChecked == true)
{
originalElement = (Path)e.Source;
DeleteShape(originalElement);
}
}
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (rbSquare.IsChecked == true)
AddSquare(startPoint, currentPoint);
else if (rbRectangle.IsChecked == true)
AddRectangle(startPoint, currentPoint);
else if (rbCircle.IsChecked == true)
AddCircle(startPoint, currentPoint);
else if (rbEllipse.IsChecked == true)
AddEllipse(startPoint, currentPoint);
if (rubberBand != null)
{
canvas1.Children.Remove(rubberBand);
rubberBand = null;
canvas1.ReleaseMouseCapture();
}
if (rbSelect.IsChecked == true)
{
if (isDown)
{
DragFinishing(false);
e.Handled = true;
}
}
}
private void AddSquare(Point point, Point currentPoint1)
{
Path path = new Path();
path.Fill = fillColor;
path.Stroke = borderColor;
RectangleGeometry rg = new RectangleGeometry();
double width = Math.Abs(point.X - currentPoint1.X);
double height = Math.Abs(point.Y - currentPoint1.Y);
double left = Math.Min(point.X, currentPoint1.X);
double top = Math.Min(point.Y, currentPoint1.Y);
double side = width;
if (width > height)
side = height;
rg.Rect = new Rect(left, top, side, side);
path.Data = rg;
paths.Add(path);
canvas1.Children.Add(paths[paths.Count - 1]);
}
private void AddRectangle(Point point, Point currentPoint1)
{
Path path = new Path();
path.Fill = fillColor;
path.Stroke = borderColor;
RectangleGeometry rg = new RectangleGeometry();
double width = Math.Abs(point.X - currentPoint1.X);
double height = Math.Abs(point.Y - currentPoint1.Y);
double left = Math.Min(point.X, currentPoint1.X);
double top = Math.Min(point.Y, currentPoint1.Y);
rg.Rect = new Rect(left, top, width, height);
path.Data = rg;
paths.Add(path);
canvas1.Children.Add(paths[paths.Count - 1]);
}
private void AddCircle(Point point, Point currentPoint1)
{
Path path = new Path();
path.Fill = fillColor;
path.Stroke = borderColor;
EllipseGeometry eg = new EllipseGeometry();
double width = Math.Abs(point.X - currentPoint1.X);
double height = Math.Abs(point.Y - currentPoint1.Y);
double left = Math.Min(point.X, currentPoint1.X);
double top = Math.Min(point.Y, currentPoint1.Y);
double side = width;
if (width > height)
side = height;
eg.Center = new Point(left + side / 2,
top + side / 2);
eg.RadiusX = side / 2;
eg.RadiusY = side / 2;
path.Data = eg;
paths.Add(path);
canvas1.Children.Add(paths[paths.Count - 1]);
}
private void AddEllipse(Point point, Point currentPoint1)
{
Path path = new Path();
path.Fill = fillColor;
path.Stroke = borderColor;
EllipseGeometry eg = new EllipseGeometry();
double width = Math.Abs(point.X - currentPoint1.X);
double height = Math.Abs(point.Y - currentPoint1.Y);
double left = Math.Min(point.X, currentPoint1.X);
double top = Math.Min(point.Y, currentPoint1.Y);
eg.Center = new Point(left + width / 2,
top + height / 2);
eg.RadiusX = width / 2;
eg.RadiusY = height / 2;
path.Data = eg;
paths.Add(path);
canvas1.Children.Add(paths[paths.Count - 1]);
}
private void DragFinishing(bool cancel)
{
Mouse.Capture(null);
if (isDragging)
{
if (!cancel)
{
currentPoint = Mouse.GetPosition(canvas1);
TranslateTransform tt0 = new TranslateTransform();
TranslateTransform tt = new TranslateTransform();
tt.X = currentPoint.X - startPoint.X;
tt.Y = currentPoint.Y - startPoint.Y;
Geometry geometry =
(RectangleGeometry)new RectangleGeometry();
string s = originalElement.Data.ToString();
if (s == "System.Windows.Media.EllipseGeometry")
geometry = (EllipseGeometry)originalElement.Data;
else if (s == "System.Windows.Media.RectangleGeometry")
geometry = (RectangleGeometry)originalElement.Data;
else if (s == "System.Windows.Media.CombinedGeometry")
geometry = (CombinedGeometry)originalElement.Data;
if (geometry.Transform.ToString() != "Identity")
{
tt0 = (TranslateTransform)geometry.Transform;
tt.X += tt0.X;
tt.Y += tt0.Y;
}
geometry.Transform = tt;
canvas1.Children.Remove(originalElement);
originalElement = new Path();
originalElement.Fill = fillColor;
originalElement.Stroke = borderColor;
originalElement.Data = geometry;
canvas1.Children.Add(originalElement);
}
canvas1.Children.Remove(movingElement);
movingElement = null;
}
isDragging = false;
isDown = false;
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (canvas1.IsMouseCaptured)
{
currentPoint = e.GetPosition(canvas1);
if (rubberBand == null)
{
rubberBand = new Rectangle();
rubberBand.Stroke = Brushes.LightCoral;
rubberBand.StrokeDashArray =
new DoubleCollection(new double[] { 4, 2 });
if (rbSquare.IsChecked == true ||
rbRectangle.IsChecked == true ||
rbCircle.IsChecked == true ||
rbEllipse.IsChecked == true)
{
canvas1.Children.Add(rubberBand);
}
}
double width = Math.Abs(
startPoint.X - currentPoint.X);
double height = Math.Abs(
startPoint.Y - currentPoint.Y);
double left = Math.Min(
startPoint.X, currentPoint.X);
double top = Math.Min(
startPoint.Y, currentPoint.Y);
rubberBand.Width = width;
rubberBand.Height = height;
Canvas.SetLeft(rubberBand, left);
Canvas.SetTop(rubberBand, top);
if (rbSelect.IsChecked == true)
{
if (isDown)
{
if (!isDragging && Math.Abs(currentPoint.X - startPoint.X) >
SystemParameters.MinimumHorizontalDragDistance &&
Math.Abs(currentPoint.Y - startPoint.Y) >
SystemParameters.MinimumVerticalDragDistance)
DragStarting();
if (isDragging)
DragMoving();
}
}
}
}
private void DragMoving()
{
currentPoint = Mouse.GetPosition(canvas1);
TranslateTransform tt = new TranslateTransform();
tt.X = currentPoint.X - startPoint.X;
tt.Y = currentPoint.Y - startPoint.Y;
movingElement.RenderTransform = tt;
}
private void DragStarting()
{
isDragging = true;
movingElement = new Path();
movingElement.Data = originalElement.Data;
movingElement.Fill = selectFillColor;
movingElement.Stroke = selectBorderColor;
canvas1.Children.Add(movingElement);
}
private void DeleteShape(Path path)
{
path.Stroke = selectBorderColor;
string msg =
"Do you really want to delete this shape?";
string title = "Delete Shape?";
MessageBoxButton buttons = MessageBoxButton.YesNo;
MessageBoxImage icon = MessageBoxImage.Warning;
MessageBoxResult result =
MessageBox.Show(msg, title, buttons, icon);
if (result == MessageBoxResult.Yes)
canvas1.Children.Remove(path);
else
{
path.Stroke = borderColor;
return;
}
}
private void SetCombineShapes(MouseButtonEventArgs e)
{
if (path1.Name != "path1Selected")
{
path1 = (Path)e.Source;
path1.Cursor = Cursors.Hand;
path1.Stroke = selectBorderColor;
path1.Name = "path1Selected";
}
else
{
if (path2 != null)
{
path2.Stroke = borderColor;
path2.Cursor = Cursors.Arrow;
}
path2 = (Path)e.Source;
path2.Cursor = Cursors.Hand;
path2.Stroke = selectBorderColor;
ContextMenu cm = new ContextMenu();
path2.ContextMenu = cm;
MenuItem mi = new MenuItem();
mi.Header = "Union";
mi.Click +=
new RoutedEventHandler(Union_Click);
cm.Items.Add(mi);
mi = new MenuItem();
mi.Header = "Xor";
mi.Click +=
new RoutedEventHandler(Xor_Click);
cm.Items.Add(mi);
mi = new MenuItem();
mi.Header = "Intersect";
mi.Click +=
new RoutedEventHandler(Intersect_Click);
cm.Items.Add(mi);
mi = new MenuItem();
mi.Header = "Exclude";
mi.Click +=
new RoutedEventHandler(Exclude_Click);
cm.Items.Add(mi);
}
}
private void Union_Click(
object sender, RoutedEventArgs e)
{
CombineShapes(path1, path2, "Union");
path1.Name = "";
}
private void Xor_Click(object sender,
RoutedEventArgs e)
{
CombineShapes(path1, path2, "Xor");
path1.Name = "";
}
private void Intersect_Click(object sender,
RoutedEventArgs e)
{
CombineShapes(path1, path2, "Intersect");
path1.Name = "";
}
private void Exclude_Click(object sender,
RoutedEventArgs e)
{
CombineShapes(path1, path2, "Exclude");
path1.Name = "";
}
private void CombineShapes(Path p1, Path p2, string s)
{
Path myPath = new Path();
myPath.Fill = fillColor;
myPath.Stroke = borderColor;
CombinedGeometry cg = new CombinedGeometry();
if (s == "Union")
cg.GeometryCombineMode =
GeometryCombineMode.Union;
else if (s == "Xor")
cg.GeometryCombineMode =
GeometryCombineMode.Xor;
else if (s == "Intersect")
cg.GeometryCombineMode =
GeometryCombineMode.Intersect;
else if (s == "Exclude")
cg.GeometryCombineMode =
GeometryCombineMode.Exclude;
cg.Geometry1 = p1.Data;
cg.Geometry2 = p2.Data;
myPath.Data = cg;
paths.Add(myPath);
canvas1.Children.Add(paths[paths.Count - 1]);
canvas1.Children.Remove(p1);
canvas1.Children.Remove(p2);
}
}
reference : Practical WPF Graphics Programming