开发者

How to implement custom undo in TextBox

I'd like to manually implement a basic undo system f开发者_JS百科or a TextBox (because of the problems mentioned in my last question). I've been trying to do this for hours, but I can't find a way. Does anybody know whether this is possible?

It seems that doing this would require, for example, detecting that the user has changed the caret position, but I can't figure out how to do this. Sure, I can listen for the arrow keys, and detect mouse clicks, but it doesn't seem to be possible — at least in the case of the arrow keys — to actually tell whether SelectionStart has changed.

If anyone has any ideas, I'd grateful.

Tom


This is a solution I developed and works fine for me:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace INQ_adm.Forms.ControlsX
{
    public class TextBoxX : TextBox
    {
        private static int UNDO_LIMIT = 0;
        private List<Item> LastData = new List<Item>();
        private int undoCount = 0;
        private Boolean undo = false;

        public TextBoxX()
        {
            InitializeComponent();
        }

       protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == (Keys.Control | Keys.Z))
            {
                undo = true;
                try
                {
                    ++undoCount;
                    this.Text = LastData[LastData.Count - undoCount - 1].text;
                    this.SelectionStart = LastData[LastData.Count - undoCount - 1].position;
                    this.PerformLayout();
                }
                catch
                {
                    --undoCount;
                }

                undo = false;
                return true;
            }

            if (keyData == (Keys.Control | Keys.Y))
            {
                undo = true;
                try
                {
                    --undoCount;
                    this.Text = LastData[LastData.Count - undoCount + 1].text;
                    this.SelectionStart = LastData[LastData.Count - undoCount + 1].position;
                    this.PerformLayout();
                }
                catch
                {
                    ++undoCount;
                }

                undo = false;
                return true;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void textBoxX_TextChanged(object sender, EventArgs e)
        {
            if (!undo)
            {
                LastData.RemoveRange(LastData.Count - undoCount, undoCount);
                LastData.Add(new Item(this.Text, this.SelectionStart));
                undoCount = 0;
                    if (UNDO_LIMIT != 0 && UNDO_LIMIT + 1 < LastData.Count)
                {
                    LastData.RemoveAt(0);
                }
            }
        }

        private void InitializeComponent()
        {
            this.TextChanged += new System.EventHandler(this.textBoxX_TextChanged);
        }
    }

    public class Item
    {
        public String text;
        public int position;

        public Item(String text, int position)
        {
            this.text = text;
            this.position = position;
        }
    }
}


Can you handle the TextChanged event and just push the textbox contents onto a stack each time it changes, then pop and refresh the TextBox every time the user hits Ctrl-Z?


This is a bit old, but sounds exactly like what you need: http://msmvps.com/blogs/peterritchie/archive/2006/09/10/Changing-TextBox-Text-as-an-Undo_2D00_able-Action.aspx

To sum up, when you do your tab replacement, simply select all of the text in the box append your 4 spaces, then paste the entire text back in the box.

This should allow the user to hit ctrl+z to undo the whole thing. Now, I have no idea what would happen if they kept typing after doing the spaces... I assume it would all get removed from a ctrl+z press.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜