33

元に戻す/やり直し機能を実装したい TextBox があります。既に若干の元に戻す機能があるかもしれないと読みましたが、バグがありますか? とにかく、元に戻す機能とやり直し機能の両方を実装して、先に進む方法を学びたいと思います。

Memento パターンについて読み、CodeProjectのGeneric Undo/Redoの例をいくつか調べました。そして、パターン kiiind は理にかなっています。それを実装する方法について頭を悩ませているようには見えません。そして、 a のコンテンツに対して効率的にそれを行う方法TextBox

もちろん、 textbox.Textwhenだけを格納することもできますが、大量のテキストが含まれているTextChanges場合は特に、大量のメモリを非常に高速に占有してしまいます。TextBox

とにかく、この機能を実装するための適切で明確で効率的な方法を実装する方法について、アドバイスを探しています。一般的にも、特に TextBox の場合も c",)

4

7 に答える 7

19

.NETSystem.ComponentModel名前空間にはIEditableObjectインターフェイスが付属しており、INotifyPropertyChangingとを使用することもできますINotifyPropertyChanged。MVC パターンはまた、インターフェイスがイベントを通じてモデルの変更に応答し、テキスト ボックスの値を更新または復元するようにします。

効果的にメメントパターン

これらを調べたことはありますか? ここに方法があります。

シンプルで迅速なバージョンは、 textbox の状態を保存することOnTextChangedです。元に戻すたびに、配列内の最後のイベントが返されます。ここでは、C# スタック タイプが便利です。インターフェイスをオフにした後、または後に状態をクリアすることもできますApply

于 2009-02-28T09:41:20.497 に答える
9

最小限のコードでそれを実現する方法は次のとおりです: (これは、単一のテキストボックスを持つ勝利フォームの背後にあるコードです)

public partial class Form1 : Form
{
    Stack<Func<object>> undoStack = new Stack<Func<object>>(); 
    public Form1()
    {
        InitializeComponent();
    }
    private void textBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.U && Control.ModifierKeys == Keys.Control && undoStack.Count > 0)
            undoStack.Pop()();            
    }
    private void textBox_KeyPress(object sender, KeyPressEventArgs e)
    {            
        if (e.KeyChar != 'u' || Control.ModifierKeys != Keys.Control)
        {
            var textBox = (TextBox)sender;
            undoStack.Push(textBox.Text(textBox.Text));
        }
    }
}
public static class Extensions
{
    public static Func<TextBox> Text(this TextBox textBox, string text)
    {            
        return () => { textBox.Text = text; return textBox; };
    }
}

他の入力タイプの拡張メソッドを実装することにより、undoStack は UI 全体を処理し、すべての UI アクションを順番に元に戻すことができます。

于 2010-09-14T02:57:18.287 に答える
3

これは、このトピックで私が見つけた最も役立つページであり、より一般的で、undo/redoスタックのさまざまなオブジェクトタイプに適しています。

コマンドパターン

それを実装するようになったとき、私はそれがどれほどシンプルでエレガントになってしまったかに驚きました。それは私にとって勝利になります。

于 2012-11-13T07:22:29.463 に答える
3

良い解決策はここにあります:

元に戻す/やり直しまたは戻る/進む機能をアプリケーションに追加する

元に戻す/やり直し可能な TextBox (winform)

コードは VB.NET ですが、それほど手間をかけずに簡単に C# に変換できます。オンラインコンバーターも利用できます。

于 2012-04-20T11:56:42.870 に答える
1

I would listen for a change event, and when it occurs push the diff of the previous state and present state onto a stack. The diffs should be much smaller than storing the entire text. Also, you might not want to push a new undo state onto the stack at every edit... I'd lump all typing together until the user changes the cursor position, for example.

于 2010-09-14T03:39:51.247 に答える
1

最も賢明な方法は、不変の永続オブジェクトを使用することです。オブジェクトに変更を加えるのではなく、古いバージョンからわずかに変更された新しいオブジェクトのみを作成します。これは、ホット パス上のツリーの一部のみを複製することで、ある程度効率的に実行できます。

最小限のコードで書かれた元に戻すスタックの例があります

 [Fact]
public void UndoStackSpec()
{
    var stack = new UndoStack<A>(new A(10, null));

    stack.Current().B.Should().Be(null);

    stack.Set(x => x.B, new B(20, null));

    stack.Current().B.Should().NotBe(null);
    stack.Current().B.P.Should().Be(20);

    stack.Undo();

    stack.Current().B.Should().Be(null);

}

ここで、A と Bprivate settersはすべてのプロパティを持つクラスとして、つまり immutable

class A : Immutable
{
    public int P { get; private set; }
    public B B { get; private set; }
    public A(int p, B b)
    {
        P = p;
        B = b;
    }
}

class B : Immutable
{
    public int P { get; private set; }
    public C C { get; private set; }
    public B(int p, C c)
    {
        P = p;
        C = c;
    }
}

class C : Immutable
{
    public int P { get; private set; }
    public C(int p)
    {
        P = p;
    }
}

ここで完全なソースを見つけることができますhttps://gist.github.com/bradphelan/5395652

于 2013-04-16T13:19:06.163 に答える