Showing posts with label Undo/Redo. Show all posts
Showing posts with label Undo/Redo. Show all posts

Wednesday, August 8, 2007

Interesting Undo/Redo solution

A few weeks ago i found a very peculiar Undo/Redo solution here .

The way it was written surprised me. It even took me 2 or 3 minutes to get the idea how the code works :).

All the magic is hidden inside a UndoRedo class. The idea is that instead of creating your variables directly, you wrap them with UndoRedo class like this:


readonly UndoRedo name = new UndoRedo();
public string Name
{
get { return name.Value; }
set { name.Value = value; }
}



This solution is very interesting, but, from my perspective, it asks too much from the programmer. To use this UndoRedo mechanism you would require to rewrite all your classes, which needs capabality of UndoRedo.

What is more, you could not make TextBox undoable, without overriding the TextBox class. And of course we know, that some classes in M$ field are for some mysterious reason sealed, so you can not inherit.

But overall, the solution is interesting, and it does work :)

Monday, May 28, 2007

Undo / Redo galimybės programoje (2 dalis)

Ankščiau rašiau apie tai, kad mūsų kuriamoje desktop programoje reikia galimybės atšaukti naudotojo padarytus veiksmus.

Nors API undo atžvilgiu dar nėra iki galo nusistovėjusi (tiesą sakant, undo mechanizmas šiek tiek *nervina*, nes jam *palaikyti* reikia tam tikrų pastangų), sprendimas yra.

Sprendimas veikia, ir štai kaip jis maždaug atrodo.

Undo mechanizmui užtenka turėti sąrašą objektų, kurie gali atstatyti naują būseną į seną būseną. Tarkime, IMemento:


///
/// An interface for all undo / redo actions
///

public interface IMemento
{
///
/// Restores the state of the object.
///

/// A new memento, which performs the Redo action
IMemento Restore();
}


Kiekvienas IMememtno Restore() metode atstato kokią nors informaciją į prieš tai buvusį būvį.

Man kol kas prireikė dviejų memento tipų:
PropertyMenento - atstato bet kurio properčio reikšmę į prieš tai buvusį
DelegateMemento - lengvai kustomizuojamas memento per delegatus

Monday, April 2, 2007

Undo / Redo galimybės programoje

Šiuo metu kuriame paprastą biuro programą.

Reikia sukurti tokius langus: mokymo dalyko langą, ir mokymo pamokų langą.
Be visų duomenų įvedimo laukų, langas turi turėti mygtukus išsaugoti ir uždaryti. Jei paspaudžiamas mygtukas išsaugoti, tai visi esami pakeitimai išsaugomi. Jei paspaudžiamas uždaryti, tai neišsaugoti pakeitimai turi būti atmesti ir langas uždarytas. Išsaugoti pakeitimai turi likti nepakitę.

Registruojant arba redaguojant mokymo pamokas, visi pakeitimai paspaudus mygtuką "išsaugoti" turi būti išsaugoti tik atmintyje. Į duomenų bazę pakeitimai siunčiami tuomet, kai saugomas pats dalykas.


Taigi, klausimas (labai jau daug išsiplėčiau apie probleminę sritį):
Kaip galima kokybiškai realizuoti Undo mechanizmą?


Ieškojau porą dienų sprendimo. Kol kas atsakymas matau yra toks: Memento design pattern'as.

Gerą pavyzdį radau čia:
Generic undo redo

Autorius siūlo tokį sprendimį: "an object that is capable of restoring a target object to one of its previous states".

Pavyzdys su c# būtų toks:

interface IMemento
{
///
/// Restores target to the state memorized by this memento.
///

///
/// A memento of the state before restoring
///

IMemento Restore(T target);
}



Sprendimas su Memento būtų turėti kiekvienam veiksmui atstatymo veiksmą. Atstatymo sprendimai gali būti dviejų rūšių -
1 - Atsatyti objektą darant jo deep-copy, ir vėliau originalą pakeičiant kopija
2 - Kiekvienam objekto keitimo veiksmui generuoti anti-veiksmą, t.y. veiksmą, atsatantį objektą į buvusią būseną. Tokių veiksmų būtų dvi rūšys - properčių atstatymas, ir ryšių atstatymas (objekto kūrimo ir šalinimo atveju).

Aš labiau linkstu prie antrojo varianto. Daryti objekto deep-copy gali sukelti daug problemų dėl ryšių. Atsatant objektus naudojant anti-veiksmus, viskas vyktų atvirkštine tvarka, negu tuomet, kai objektas buvo keičiamas.

Šiandieną bandysim implementuoti tokį sprendimą, žiūrėsim, kas gausis