控制撤消/重做移动和调整大小

时间:2015-06-05 12:46:08

标签: c# winforms

我正在为我的图形编辑器添加撤消/重做功能,但是我在移动和调整大小时遇到​​了一些undo / redo问题。

首先,当我移动Control(例如Ellipse)时,我点击撤消按钮Ellipse转到另一个位置。当我在撤消后按重做时Ellipse转到正确的位置。

这是一个链接,可以更清楚地表达我的意思:http://gyazo.com/d299fe5e52f08742e7fa2132f6ff9839

与第一件事有很多协议的第二件事是当我调整Control(例如Ellipse)的大小时,我点击撤消Ellipse的大小比它大应该有。再次单击重做后,它再次具有正确的大小。

这是一个链接,可以更清楚地表达我的意思:http://gyazo.com/59ecdcba751ff3b8ffd053dd19cd9945

问题可能在MoveCommandResizeCommand类中,我的代码基于此代码http://www.codeproject.com/Articles/33384/Multilevel-Undo-and-Redo-Implementation-in-Cshar。在链接页面中,他们使用WPFThickness用于移动/调整大小。在WinForms中没有Thickness,但我还尝试了Margin / Padding,但没有运气。如何调整大小/移动撤消/重做工作?

MoveCommand.cs

class MoveCommand : ICommand
{
    Control _control;
    int _changeOfTop;
    int _changeOfLeft;

    public MoveCommand(int top, int left, Control control)
    {
        _control = control;
        _changeOfTop = top;
        _changeOfLeft = left;
    }

    public void Execute()
    {
        _control.Top = _control.Top + _changeOfTop;
        _control.Left = _control.Left + _changeOfLeft;
    }

    public void UnExecute()
    {
        _control.Top = _control.Top - _changeOfTop;
        _control.Left = _control.Left - _changeOfLeft;
    }

}

ResizeCommand.cs

class ResizeCommand : ICommand
{
    private int _changeOfWidth;
    private int _changeOfHeight;
    private Control _control;

    public ResizeCommand(int width, int height, Control control)
    {
        _changeOfWidth = width;
        _changeOfHeight = height;
        _control = control;
    }

    public void Execute()
    {
        _control.Height = _control.Height + _changeOfHeight;
        _control.Width = _control.Width + _changeOfWidth;
    }

    public void UnExecute()
    {
        _control.Height = _control.Height - _changeOfHeight;
        _control.Width = _control.Width - _changeOfWidth;
    }
}

Ellipse.cs

class Ellipse : Control
{
    private Point mDown { get; set; }
    private Point conLoc { get; set; }
    private bool userResizing = false;
    private Form1 form =null;

    public Ellipse(Form1 form1)
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        this.BackColor = Color.Transparent;
        this.DoubleBuffered = true;
        this.ResizeRedraw = true;
        this.form = form1;
    }


    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;
        conLoc = this.Location;
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        base.OnMouseUp(e);
        if (this.Location != conLoc)
        {
            Console.WriteLine("You moved me");
            this.form.InsertInUnDoRedoForMove(conLoc.Y, conLoc.X, this);
        }

    }

    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;
        const int WM_EXITSIZEMOVE = 0x232;
        const int WM_NCLBUTTONDWN = 0xA1;

        if (m.Msg == WM_NCLBUTTONDWN)
        {
            if (!userResizing)
            {
                userResizing = true;
                Console.WriteLine("Start Resizing");
                this.form.InsertInUnDoRedoForResize(this.Width, this.Height, this);
            }
        }
        else if (m.Msg == WM_EXITSIZEMOVE)
        {
            if (userResizing)
            {
                userResizing = false;
                Console.WriteLine("Finish Resizing");
            }
        }
        else 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);
    }
}

Form1.cs的

public partial class Form1 : Form
{
    private bool draw;
    private int x, y, xe, ye;

    private Stack<ICommand> _Undocommands = new Stack<ICommand>();
    private Stack<ICommand> _Redocommands = new Stack<ICommand>();


    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(this);
                panel.Controls.Add(box);
                box.Location = new Point(x, y);
                box.Width = (xe - x);
                box.Height = (ye - y);
                //InsertCommand boxcmd = new InsertCommand(box, panel);
                InsertInUnDoRedoForInsert(box);
                break;
            case Item.Ellipse:
                var el = new Ellipse(this);
                panel.Controls.Add(el);
                el.Location = new Point(x, y);
                el.Width = (xe - x);
                el.Height = (ye - y);
                //InsertCommand elcmd = new InsertCommand(el,panel);
                InsertInUnDoRedoForInsert(el);
                break;
            default:
                break;
        }
    }

    private void undoButton_Click(object sender, EventArgs e)
    {
        Undo(1);
    }

    private void redoButton_Click(object sender, EventArgs e)
    {
        Redo(1);
    }

    private void clearAllButton_Click(object sender, EventArgs e)
    {
        commandList.Clear();
        current = 0;
        panel.Controls.Clear();
    }

    public void Redo(int levels)
    {
        for (int i = 1; i <= levels; i++)
        {
            if (_Redocommands.Count != 0)
            {
                ICommand command = _Redocommands.Pop();
                command.Execute();
                _Undocommands.Push(command);
            }
            Invalidate();
        }
    }

    public void Undo(int levels)
    {
        for (int i = 1; i <= levels; i++)
        {
            if (_Undocommands.Count != 0)
            {
                ICommand command = _Undocommands.Pop();
                command.UnExecute();
                _Redocommands.Push(command);
            }
            Invalidate();
        }
    }

    #region UndoHelperFunctions
    public void InsertInUnDoRedoForInsert(Control control)
    {
        ICommand cmd = new InsertCommand(control, panel,shapeTreeView);
        _Undocommands.Push(cmd); _Redocommands.Clear();
    }

    public void InsertInUnDoRedoForResize
    (int width, int height, Control control)
    {
        ICommand cmd = new ResizeCommand(width, height, control);
        _Undocommands.Push(cmd); _Redocommands.Clear();
    }

    public void InsertInUnDoRedoForMove
    (int top, int left, Control control)
    {
        ICommand cmd = new MoveCommand(top,left,control);
        _Undocommands.Push(cmd); _Redocommands.Clear();
    }

    #endregion
}

0 个答案:

没有答案