C#和Winforms文本框控件:如何更改文本?

C#和Winforms文本框控件:如何更改文本?,c#,winforms,C#,Winforms,我的表单上有一个TextBox.TextChanged事件的事件处理程序。为了支持撤销,我想准确地找出文本框中发生了哪些更改,以便在用户要求时撤销更改。(我知道内置文本框支持撤销,但我希望整个应用程序都有一个撤销堆栈) 有没有一个合理的方法可以做到这一点?如果没有,是否有更好的方法支持这种撤销功能 编辑:像下面这样的方法似乎有效——有没有更好的办法?(在这种情况下,我真的希望.NET有类似STL的std::mismatch算法 class TextModification {

我的表单上有一个TextBox.TextChanged事件的事件处理程序。为了支持撤销,我想准确地找出文本框中发生了哪些更改,以便在用户要求时撤销更改。(我知道内置文本框支持撤销,但我希望整个应用程序都有一个撤销堆栈)

有没有一个合理的方法可以做到这一点?如果没有,是否有更好的方法支持这种撤销功能

编辑:像下面这样的方法似乎有效——有没有更好的办法?(在这种情况下,我真的希望.NET有类似STL的
std::mismatch
算法

    class TextModification
    {
        private string _OldValue;
        public string OldValue
        {
            get
            {
                return _OldValue;
            }
        }
        private string _NewValue;
        public string NewValue
        {
            get
            {
                return _NewValue;
            }
        }
        private int _Position;
        public int Position
        {
            get
            {
                return _Position;
            }
        }
        public TextModification(string oldValue, string newValue, int position)
        {
            _OldValue = oldValue;
            _NewValue = newValue;
            _Position = position;
        }
        public void RevertTextbox(System.Windows.Forms.TextBox tb)
        {
            tb.Text = tb.Text.Substring(0, Position) + OldValue + tb.Text.Substring(Position + NewValue.Length);
        }
    }

    private Stack<TextModification> changes = new Stack<TextModification>();
    private string OldTBText = "";
    private bool undoing = false;

    private void Undoit()
    {
        if (changes.Count == 0)
            return;
        undoing = true;
        changes.Pop().RevertTextbox(tbFilter);
        OldTBText = tbFilter.Text;
        undoing = false;
    }

    private void UpdateUndoStatus(TextBox caller)
    {
        int changeStartLocation = 0;
        int changeEndTBLocation = caller.Text.Length;
        int changeEndOldLocation = OldTBText.Length;
        while (changeStartLocation < Math.Min(changeEndOldLocation, changeEndTBLocation) &&
            caller.Text[changeStartLocation] == OldTBText[changeStartLocation])
            changeStartLocation++;
        while (changeEndTBLocation > 1 && changeEndOldLocation > 1 &&
            caller.Text[changeEndTBLocation-1] == OldTBText[changeEndOldLocation-1])
        {
            changeEndTBLocation--;
            changeEndOldLocation--;
        }
        changes.Push(new TextModification(
            OldTBText.Substring(changeStartLocation, changeEndOldLocation - changeStartLocation),
            caller.Text.Substring(changeStartLocation, changeEndTBLocation - changeStartLocation),
            changeStartLocation));
        OldTBText = caller.Text;
    }

    private void tbFilter_TextChanged(object sender, EventArgs e)
    {
        if (!undoing)
            UpdateUndoStatus((TextBox)sender);
    }
类文本修改
{
私有字符串_OldValue;
公共字符串值
{
得到
{
返回旧值;
}
}
私有字符串_NewValue;
公共字符串NewValue
{
得到
{
返回_NewValue;
}
}
私人国际职位;
公共int位置
{
得到
{
返回位置;
}
}
公共文本修改(字符串oldValue、字符串newValue、int位置)
{
_OldValue=OldValue;
_NewValue=NewValue;
_位置=位置;
}
公共文本框(System.Windows.Forms.TextBox)
{
tb.Text=tb.Text.Substring(0,位置)+OldValue+tb.Text.Substring(位置+NewValue.Length);
}
}
私有堆栈更改=新堆栈();
私有字符串OldTBText=“”;
私有布尔撤销=假;
私有无效撤消它()
{
如果(changes.Count==0)
返回;
撤销=正确;
changes.Pop().RevertTextbox(tbFilter);
OldTBText=tbFilter.Text;
撤销=错误;
}
私有void updateEndostatus(文本框调用方)
{
int=0;
int changeEndTBLocation=caller.Text.Length;
int changeendollocation=oldtbttext.Length;
while(changeStartLocation1&&changeendldlocation>1&&
caller.Text[changeEndTBLocation-1]==oldtbttext[changeendollocation-1])
{
changeEndTBLocation--;
改变位置--;
}
更改。推送(新文本修改)(
OldTBText.Substring(changeStartLocation、changeEndOldLocation-changeStartLocation),
caller.Text.Substring(changeStartLocation,changeEndTBLocation-changeStartLocation),
改变位置);
OldTBText=caller.Text;
}
私有无效tbFilter_TextChanged(对象发送方,事件参数e)
{
如果(!撤消)
UpdateEndostatus((文本框)发送方);
}

是的,不要将其直接绑定到文本框。表单的状态应该在某个不直接绑定到表单的模型对象中(MVC是一种方式,MVVM是另一种方式)。通过这样解耦它们,您可以在收到更改请求时将新文本框值与当前模型值进行比较。

您最好使用Enter和Leave事件。输入时,将当前文本存储在类变量中,然后在离开时将新文本与旧文本进行比较。

事实上,我所能想到的是当然,有一种集合可以存储不同的字符串版本(因此可以多次撤消,而不是一次撤消)。 我会将对TextBox集合的引用存储在TextBox.Tag中,因此存储/使用它很简单


最后但并非最不重要的一点是,您可以在事件TextChange期间更新字符串集合。无需做太多工作,您就可以维护完整的历史记录,从您自己的结构中获取以前的值。

这对于您试图完成的任务来说可能有些过分,但支持n级撤消。CSLA是Ro编写的一个很棒的业务对象框架业务对象处理撤销历史,并通过数据绑定流到UI


切换你的应用程序使用CSLA将是一个巨大的承诺,但另一个选择是查看免费提供的源代码,看看他是如何实现它的。

我实际上正在制作一个自己的语法突出显示系统,因此我还需要知道更改后的文本。 我的解决方案是观察光标的进入、空格或沉积。 由于WinForms提供Keydown事件,我使用了KeyEventArguments(e)和

之后,我将字符存储到如下字符串中:

string i=“”;
i+=convertedToChar;//convertedToChar=kc.ConvertToString(例如KeyData)

一旦有进入、空间或沉积——“事件”,我就删除字符串

结果: 如果用户输入几个字符并点击空格,我就能读取最后一个字符(直到最后一个空格)。 一个优点是,您可以使用任何分隔符char(只要e.KeyCode存储并提供了分隔符char)

然而,我希望这是一个解决方案,让每个人在9年后都能看到:D。
这永远不会太迟。

是的,我知道。问题是要进行实际的比较。考虑到文本更改事件可以在以下情况下触发:a.键入字符,B.删除字符,或C.替换一段文本(即粘贴在hilight上),没有通用的方法来解决这个问题。如果可以的话,我宁愿避免启发式。但是,每次有人键入一个字符,我都需要存储文本框的全部内容。这将是一个巨大的问题。注意:如果我不必将大量的字符保存到磁盘,那么巨大的字符不会困扰我。您将在输入和离开时遇到问题。有一个NTI模式指事件的过度使用。@Da