I have two custom Control
classes, Box
and Ellipse
. I'm able to draw, drag and resize them. Now I'm trying to implement unlimited undo and redo. I use the Command Pattern
for this. My Box
class look exactly the same as the Ellipse
class with the difference that the Box
class paints a box shape. At the moment when I paint an Ellipse
and for example move /resize this control I'm able to go one step back, because adding makes the stacksize 1 and one undo makes the stacksize 0 again. Only when I add the Ellipse
I push the command to the Stack
now. The resizing/moving happens in another class then the adding, but these actions also have to be pushed to the commandStack
in Form1
. How can I do this?
My idea was to create a stack in Ellipse
and Box
and call Do
for every action and push every command to the stack (in Ellipse
or Box
), but this isn't gonna work I believe because the Form
class needs to have access to the stack with all commands from all Controls
. Anyone who can help to make unlimited undo/redo work? I followed the example in this link: http://ift.tt/1RdUEei .
ICommand interface
public interface ICommand
{
void Do();
void Undo();
}
Ellipse class
class Ellipse : Control, ICommand
{
private Point mDown { get; set; }
public Ellipse()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.DoubleBuffered = true;
this.ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Draw a black ellipse in the rectangle represented by the control.
e.Graphics.FillEllipse(Brushes.Black, 0, 0, Width, Height);
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
mDown = e.Location;
}
protected override void OnMouseMove(MouseEventArgs e)
{
// Call MyBase.OnMouseMove to activate the delegate.
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left)
{
Location = new Point(e.X + Left - mDown.X, e.Y + Top - mDown.Y);
}
}
/* Allow resizing at the bottom right corner */
protected override void WndProc(ref Message m)
{
const int wmNcHitTest = 0x84;
const int htBottomLeft = 16;
const int htBottomRight = 17;
if (m.Msg == wmNcHitTest)
{
int x = (int)(m.LParam.ToInt64() & 0xFFFF);
int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);
Point pt = PointToClient(new Point(x, y));
Size clientSize = ClientSize;
if (pt.X >= clientSize.Width - 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
{
m.Result = (IntPtr)(IsMirrored ? htBottomLeft : htBottomRight);
return;
}
}
base.WndProc(ref m);
}
int x;
int y;
int height;
int width;
private void SaveCurrentControl()
{
x = this.Left;
y = this.Top;
height = this.Height;
width = this.Width;
}
public void Do()
{
SaveCurrentControl();
}
public void Undo()
{
this.Left = x;
this.Top = y;
this.Height = height;
this.Width = width;
}
}
Form class
public partial class Form1 : Form
{
private bool draw;
private int x, y, xe, ye;
private Stack<ICommand> commandStack = new Stack<ICommand>();
ICommand command = null;
public Form1()
{
InitializeComponent();
menuComboBoxShape.ComboBox.DataSource = Enum.GetValues(typeof(Item));
}
public enum Item
{
Pencil,
Rectangle,
Ellipse,
}
private void panel_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
x = e.X;
y = e.Y;
}
private void panel_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
xe = e.X;
ye = e.Y;
Item item;
Enum.TryParse<Item>(menuComboBoxShape.ComboBox.SelectedValue.ToString(), out item);
switch (item)
{
case Item.Pencil:
using (Graphics g = panel.CreateGraphics())
using (var pen = new Pen(System.Drawing.Color.Black)) //Create the pen used to draw the line (using statement makes sure the pen is disposed)
{
g.DrawLine(pen,new Point(x, y), new Point(xe, ye));
}
break;
case Item.Rectangle:
var box=new Box();
panel.Controls.Add(box);
box.Location = new Point(x, y);
box.Width = (xe - x);
box.Height = (ye - y);
break;
case Item.Ellipse:
var el = new Ellipse();
panel.Controls.Add(el);
el.Location = new Point(x, y);
el.Width = (xe - x);
el.Height = (ye - y);
el.Do();
commandStack.Push(el);
break;
default:
break;
}
}
private void undoButton_Click(object sender, EventArgs e)
{
if (commandStack.Count > 0)
{
ICommand lastCommand = commandStack.Pop();
lastCommand.Undo();
}
panel.Invalidate();
}
private void clearAllButton_Click(object sender, EventArgs e)
{
panel.Controls.Clear();
}
}
Aucun commentaire:
Enregistrer un commentaire