undo(отмена действий) wpf c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;
using System.Diagnostics;
namespace VectorGraphicEditor
{
public partial class MainWindow : Window
{
Pen[] pen;
List<List<Line>> freelines;
int point_index = 0;
Line line_cur = null;
bool pen_mode = false;
String mode="";
Point currentPoint = new Point();
int cnt = 0,l_cnt=0;
double x1, y1;
private Point startPoint;
private Rectangle rectangle;
private Ellipse circle;
public MainWindow()
{
freelines = new List<List<Line>>(100);
for (int i = 0; i < 100; i++)
freelines.Add(new List<Line>(100)) ;
x1 = y1 = 0;
InitializeComponent();
pen = new Pen[100];
for (int i = 0; i < 100; i++)
pen[i]=new Pen(SystemColors.WindowFrameBrush,2f);
paintSurface.Background = new SolidColorBrush(Colors.White);
}
private void paintSurface_MouseUp(object sender, MouseButtonEventArgs e)
{
circle = null;
rectangle = null;
if (!pen_mode)
cnt++;
else l_cnt++;
}
private void paintSurface_MouseDown(object sender,MouseButtonEventArgs e)
{
if (mode == "rectangle")
{
startPoint = e.GetPosition(paintSurface);
rectangle = new Rectangle
{
Stroke = pen[cnt].Brush,
StrokeThickness = pen[cnt].Thickness
};
Canvas.SetLeft(rectangle, startPoint.X);
Canvas.SetTop(rectangle, startPoint.Y);
paintSurface.Children.Add(rectangle);
}
else if (mode == "circle")
{
startPoint = e.GetPosition(paintSurface);
circle = new Ellipse
{
Stroke = pen[cnt].Brush,
StrokeThickness = pen[cnt].Thickness
};
Canvas.SetLeft(circle, startPoint.X);
Canvas.SetTop(circle, startPoint.Y);
paintSurface.Children.Add(circle);
}
if (pen_mode)
{
x1 = e.GetPosition(this).X;
y1 = e.GetPosition(this).Y;
}
else
{
double marker_x = -1, marker_y = -1;
if (e.LeftButton == MouseButtonState.Pressed)
currentPoint = e.GetPosition(this);
Line line;
foreach (Line line1 in paintSurface.Children.OfType<Line>())
{
line = line1;
if (Math.Abs(line.X1 - e.GetPosition(this).X) < 5 && Math.Abs(e.GetPosition(this).Y - 106 - line.Y1) < 5)
{
point_index = 0;
marker_x = line.X1;
marker_y = line.Y1;
line_cur = line;
}
else if (Math.Abs(line.X2 - e.GetPosition(this).X) < 5 && Math.Abs(e.GetPosition(this).Y - 106 - line.Y2) < 5)
{
point_index = 1;
marker_x = line.X2;
marker_y = line.Y2;
line_cur = line;
}
}
}
}
private void paintSurface_MouseMove(object sender,MouseEventArgs e)
{
if (pen_mode)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (mode == "rectangle")
{
if (e.LeftButton == MouseButtonState.Released || rectangle == null)
return;
var pos = e.GetPosition(paintSurface);
var x = Math.Min(pos.X, startPoint.X);
var y = Math.Min(pos.Y, startPoint.Y);
var w = Math.Max(pos.X, startPoint.X) - x;
var h = Math.Max(pos.Y, startPoint.Y) - y;
rectangle.Width = w;
rectangle.Height = h;
Canvas.SetLeft(rectangle, x);
Canvas.SetTop(rectangle, y);
}
else if (mode == "circle")
{
if (e.LeftButton == MouseButtonState.Released || circle == null)
return;
var pos = e.GetPosition(paintSurface);
var x = Math.Min(pos.X, startPoint.X);
var y = Math.Min(pos.Y, startPoint.Y);
var w = Math.Max(pos.X, startPoint.X) - x;
var h = Math.Max(pos.Y, startPoint.Y) - y;
rectangle.Width = w;
rectangle.Height = h;
Canvas.SetLeft(circle, x);
Canvas.SetTop(circle, y);
}
else
{
Line line_ = new Line();
line_.X1 = e.GetPosition(this).X;
line_.Y1 = e.GetPosition(this).Y - 106;
line_.X2 = x1;
line_.Y2 = y1 - 106;
line_.StrokeThickness = pen[cnt].Thickness;
line_.Stroke = pen[cnt].Brush;
paintSurface.Children.Add(line_);
freelines[l_cnt].Add(line_);
}
x1 = e.GetPosition(this).X;
y1 = e.GetPosition(this).Y;
}
}
else {
double marker_x = -1, marker_y = -1;
if (e.LeftButton == MouseButtonState.Pressed)
{
Line line = null;
if (line_cur != null)
{
if (point_index == 0)
{
line_cur.X1 = e.GetPosition(this).X;
line_cur.Y1 = e.GetPosition(this).Y - 106;
marker_x = line_cur.X1;
marker_y = line_cur.Y1;
Console.WriteLine("Правлю точку 0");
}
else
{
line_cur.X2 = e.GetPosition(this).X;
line_cur.Y2 = e.GetPosition(this).Y - 106;
marker_x = line_cur.X2;
marker_y = line_cur.Y2;
Console.WriteLine("Правлю точку 1");
}
for (int i = 0; i < 10; i++)
foreach (System.Windows.Shapes.Rectangle rect1 in paintSurface.Children.OfType<System.Windows.Shapes.Rectangle>())
{
if (rect1.Width == 10)
{
paintSurface.Children.Remove(rect1);
break;
}
}
System.Windows.Shapes.Rectangle rect;
rect = new System.Windows.Shapes.Rectangle();
rect.Stroke = new SolidColorBrush(Colors.Red);
rect.Fill = new SolidColorBrush(Colors.Transparent);
rect.Width = 10;
rect.Height = 10;
Canvas.SetLeft(rect, marker_x - 5);
Canvas.SetTop(rect, marker_y - 5);
paintSurface.Children.Add(rect);
return;
}
else
{
foreach (Line line1 in paintSurface.Children.OfType<Line>())
{
line = line1;
if (line.Name == "line_" + cnt)
{
break;
}
else line = null;
}
}
if (line_cur == null)
{
if (line == null)
{
line = new Line();
line.Stroke = SystemColors.WindowFrameBrush;
line.X1 = currentPoint.X;
line.Y1 = currentPoint.Y - 106;
line.X2 = e.GetPosition(this).X;
line.Y2 = e.GetPosition(this).Y - 106;
currentPoint = e.GetPosition(this);
line.Name = "line_" + cnt;
line.Stroke = pen[cnt].Brush;
line.StrokeThickness = pen[cnt].Thickness;
paintSurface.Children.Add(line);
}
else
{
line.X2 = e.GetPosition(this).X;
line.Y2 = e.GetPosition(this).Y - 106;
paintSurface.InvalidateVisual();
}
}
}
else
{
Line line = null;
foreach (Line line1 in paintSurface.Children.OfType<Line>())
{
line = line1;
if ((Math.Abs(line.X1 - e.GetPosition(this).X) < 5) && (Math.Abs(e.GetPosition(this).Y - 106 - line.Y1) < 5))
{
point_index = 0;
marker_x = line.X1;
marker_y = line.Y1;
line_cur = line;
}
else if ((Math.Abs(line.X2 - e.GetPosition(this).X)) < 5 && (Math.Abs(e.GetPosition(this).Y - 106 - line.Y2) < 5))
{
point_index = 1;
marker_x = line.X2;
marker_y = line.Y2;
line_cur = line;
}
}
}
if (marker_x != -1)
{
System.Windows.Shapes.Rectangle rect;
rect = new System.Windows.Shapes.Rectangle();
rect.Stroke = new SolidColorBrush(Colors.Red);
rect.Fill = new SolidColorBrush(Colors.Transparent);
rect.Width = 10;
rect.Height = 10;
Canvas.SetLeft(rect, marker_x - 5);
Canvas.SetTop(rect, marker_y - 5);
paintSurface.Children.Add(rect);
}
else
{
foreach (Rectangle rect in paintSurface.Children.OfType<Rectangle>())
{
if (rect.Width == 10)
{
paintSurface.Children.Remove(rect);
line_cur = null;
paintSurface.InvalidateVisual();
break;
}
}
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (mode != "erase")
{
for (int i = cnt; i < 100; i++)
pen[i].Brush = ((Button)sender).Background;
}
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
for (int i = cnt; i < 100; i++)
pen[i].Thickness = slider.Value;
}
private void NewFile(object sender, RoutedEventArgs e)
{
paintSurface.Children.Clear();
}
private void OpenFile(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dl1 = new Microsoft.Win32.OpenFileDialog();
dl1.FileName = "MYFileSave";
dl1.DefaultExt = ".png";
dl1.Filter = "Image documents (.png)|*.png";
Nullable<bool> result = dl1.ShowDialog();
if (result == true)
{
string filename = dl1.FileName;
ImageBrush brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri(@filename, UriKind.Relative));
paintSurface.Background = brush;
}
}
public static void ToImageSource(Canvas canvas, string filename)
{
RenderTargetBitmap bmp = new RenderTargetBitmap((int)canvas.ActualWidth, (int)canvas.ActualHeight, 96d, 96d, PixelFormats.Pbgra32);
canvas.Measure(new Size((int)canvas.ActualWidth, (int)canvas.ActualHeight));
canvas.Arrange(new Rect(new Size((int)canvas.ActualWidth, (int)canvas.ActualHeight)));
bmp.Render(canvas);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
using (FileStream file = File.Create(filename))
{
encoder.Save(file);
}
}
private void SaveFile(object sender, RoutedEventArgs e)
{
Microsoft.Win32.SaveFileDialog saveimg = new Microsoft.Win32.SaveFileDialog();
//Canvas can = new Canvas(); // канвас уже есть
saveimg.DefaultExt = ".PNG";
saveimg.Filter = "Image (.PNG)|*.PNG";
if (saveimg.ShowDialog() == true)
{
ToImageSource(paintSurface, saveimg.FileName); //DragArena - имя имеющегося канваса
}
}
private void Exit(object sender, RoutedEventArgs e)
{
SaveFile(sender,e);
Close();
}
private void line_Click(object sender, RoutedEventArgs e)
{
pen_mode = false;
mode = "line";
}
private void circle_Click(object sender, RoutedEventArgs e)
{
pen_mode = true;
mode = "circle";
}
private void rectangle_Click(object sender, RoutedEventArgs e)
{
pen_mode = true;
mode = "rectangle";
}
private void bucket_Click(object sender, RoutedEventArgs e)
{
}
private void eraser_Click(object sender, RoutedEventArgs e)
{
mode = "erase";
pen_mode = true;
for (int i = cnt; i < 100; i++)
{
pen[i].Brush = new SolidColorBrush(Colors.White);
pen[i].Thickness = 3f;
}
}
private void undo_Click_(object sender, RoutedEventArgs e)
{
if (paintSurface.Children.Count != 0)
paintSurface.Children.RemoveAt(paintSurface.Children.Count - 1);
else return;
}
private void Pencil_Click_(object sender, RoutedEventArgs e)
{
mode = "pen";
pen_mode = true;
for (int i = 0; i < 100; i++)
pen[i] = new Pen(SystemColors.WindowFrameBrush, 2f);
}
}
}
Делаю графический редактор.В нем есть несколько режимов(карандаш,прямые линии,прямоугольники).Отмеа происходит с помощью undo_click. С прямыми линиями и прямугольниками все более менее он их удаляет.paintSurface.Children.RemoveAt(paintSurface.Children.Count - 1); Но как-то бывает иногда не с первого раза.приходится иногда много раз жать на кнопку,не знаю с чем это связано. Но главная проблема это удаление проивзольных линий.Одна такая линия состоит из множества линий,поэтому у меня возникают трудности.Добавляю все множество линий для каждой произвольной линии в список списков freelines по индексу l_cnt.Но как правильно удалять элементы так и не понял.у меня не получается.
Как мне правильно сделать отмену произвольных линий с помощью списка списков freelines в undo_click?