C#: atestat și pregătire ONTI

C#: Undo și Redo pentru modificări controlate

Implementează Undo și Redo în C# cu două stive. Înțelege istoricul, ștergerea ramurii redo după o modificare nouă și diferența dintre stare și comandă.

O aplicație de editare trebuie să poată reveni asupra unei modificări fără să recalculeze întreaga sesiune. Pentru un model mic, păstrăm stări anterioare într-o stivă undo și stări recuperabile într-o stivă redo. Modelul este un text; pentru obiecte mutable ar fi necesare copii independente sau comenzi inverse bine definite.

Cum lucrezi cu exemplul

Programul complet folosește C# 7.3 și API-uri disponibile în .NET Framework 4.8. Deschide Lesson.csproj din arhivă sau creează un proiect Console App (.NET Framework 4.8) și înlocuiește Program.cs. Datele de demonstrație sunt incluse în cod.

Descarcă sursele și instrucțiunile.

Ideea și pașii de implementare

Set pune valoarea curentă în undo, aplică valoarea nouă și golește redo. Undo mută starea curentă în redo și extrage starea anterioară. Redo face operația simetrică. O modificare nouă după Undo creează o ramură nouă, deci vechiul viitor nu mai este disponibil.

Nu salvăm un pas dacă valoarea nouă este identică cu cea curentă. Pentru texte mari sau multe obiecte, copiile complete consumă memorie; poți limita istoricul sau folosi modelul Command, în care fiecare operație știe cum să se execute și să se inverseze.

Exemplu și rezultat așteptat

Pornim de la A, modificăm în B și apoi în C. Undo revine la B; încă un Undo revine la A. Redo reface B. Modificarea în X golește redo, iar o nouă încercare de Redo este refuzată. Programul afișează B, A, B, X și False.

Schemă pentru lecția 28: A → B → C; Undo → B; Redo → C; Editare nouă → golește redo.A → B → C → Undo → B → Redo → C → Editare nouă → golește redo.Mărește schema ↗

Codul complet

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Globalization;
using System.Xml.Linq;
using System.Data;
class History {
    readonly Stack<string> undo=new Stack<string>(),redo=new Stack<string>();
    public string Value {get;private set;}
    public History(string value) {Value=value;}
    public void Set(string value) {if(value==Value)return;undo.Push(Value);Value=value;redo.Clear();}
    public bool Undo() {if(undo.Count==0)return false;redo.Push(Value);Value=undo.Pop();return true;}
    public bool Redo() {if(redo.Count==0)return false;undo.Push(Value);Value=redo.Pop();return true;}
}
class Program {
    static void Main() {
        var h=new History("A");h.Set("B");h.Set("C");h.Undo();Console.WriteLine(h.Value);
        h.Undo();Console.WriteLine(h.Value);h.Redo();Console.WriteLine(h.Value);
        h.Set("X");Console.WriteLine(h.Value);Console.WriteLine(h.Redo());
    }
}

Rezultatul programului:

B
A
B
X
False

Greșeli și limite

Nu păstra în istoric aceeași referință la o listă modificată continuu: toate „stările” ar putea arăta identic. Nu înregistra o operație eșuată ca pas valid. Persistarea în baza de date și Undo local sunt responsabilități diferite; o anulare vizuală nu anulează automat o tranzacție deja confirmată.

Exersează

Testează Undo la început, Redo fără Undo și trei modificări identice. Istoricul nu trebuie să producă excepții sau pași inutili. Leagă modelul la două butoane și dezactivează-le când stivele respective sunt goale. Explică de ce o editare nouă după Undo trebuie să golească redo.

Continuă parcursul

Parcursul complet de 50 de lecții

Bazele C#

Lecția precedentă: C#: resurse localizate și texte fără concatenări fragile

Lecția următoare: C#: miniaplicație quiz cu răspuns unic și scor.

Referință: documentația Microsoft.

Întrebări frecvente

De ce folosesc două stive?

Una păstrează trecutul accesibil, cealaltă păstrează stările anulate care pot fi refăcute.

Pot salva doar referința la un obiect mutabil?

Nu dacă obiectul va fi modificat ulterior. Ai nevoie de copie sau de o comandă inversă corectă.

Undo local anulează automat SQL?

Nu. Trebuie proiectată explicit relația dintre istoricul interfeței și operațiile persistate.

Un pas mai departe

Autentifică-te pentru a păstra progresul în cont.

Exersează cu o problemă →