Undo functionality for Node rename in TreeView
-
I Implemented the Rename Functionality, But can some one tells me the good way to implement the Undo Functionality for rename?
How about clarifying the scenario here: 1. is this a WinForms question, and are you using the standard WinForms TreeView provided by MS ? 2. For 'Undo:' are you talking about one level of Undo, or many levels, or levels set by the end-user while running the Application ? best, Bill
"Beauty is in the eye of the beholder, and it may be necessary from time to time to give a stupid or misinformed beholder a black eye." Miss Piggy"
-
I Implemented the Rename Functionality, But can some one tells me the good way to implement the Undo Functionality for rename?
You shouldn't 'implement the Undo Functionality for rename'. You should implement undo as an app-wide thing which maintains a stack of commands across the whole application and knows how to undo them. There's two ways to do undo: either you maintain the state before each operation, or you store each operation as a command which knows how to undo itself. In all but the simplest case you want to do the second way. You need to implement every action within your application as a command, where command means something like:
interface IUndoableCommand {
void Undo();
void Redo();
}In this case, assuming your tree view is bound to some view-model level property, you would hook the NodeRenamed event (whatever it's actually called) - pseudocode:
class ItemRenameCommand : IUndoableCommand {
string oldname, newname;
INamedModel Model { get; set; }ItemRenameCommand(INamedModel model, string oldname, string newname) {
this.oldname = oldname; this.newname = newname;
Model = model;
}void Undo() { Model.Name = oldname; }
void Redo() { Model.Name = newname; }
}class MainForm : Form {
...
void TreeNodeRenamed(object sender, NodeRenameEventArgs e){
IUndoableCommand renameCommand = new ItemRenameCommand(treeViewModel, e.OldName, e.NewName);
undoStack.Push(renameCommand);
}Stack<IUndoableCommand> undoStack, redoStack;
}(Remember, pseudocode; I can't remember how you actually hook onto the rename event of a TreeView, and it's not really the main point of the discussion, but it means that won't compile.) INamedModel is just for the Name property, you'd typically have all your view model classes implement something like that in a strongly typed environment. One can have an argument about whether the undo/redo stacks should be in the UI (i.e. the view) or the view-model, taking a MVVM approach to structure. I tend to feel that because it represents user actions, it is part of the view. Then, to undo, you take items off the undo stack and call .Undo() on each of them in turn, pushing them onto the redo stack. And to redo, you take items off the redo stack, move them to the undo stack and call .Redo() on each one. The tricky bit is making sure that everything can be represented by a reversible command. For some things (simplistic example, a Reset or Randomise button) you will have to store most or all of the previous state, but avoid doing that in all cases where it is possible to do so, as storing the whole state for each undo entry is a
-
You shouldn't 'implement the Undo Functionality for rename'. You should implement undo as an app-wide thing which maintains a stack of commands across the whole application and knows how to undo them. There's two ways to do undo: either you maintain the state before each operation, or you store each operation as a command which knows how to undo itself. In all but the simplest case you want to do the second way. You need to implement every action within your application as a command, where command means something like:
interface IUndoableCommand {
void Undo();
void Redo();
}In this case, assuming your tree view is bound to some view-model level property, you would hook the NodeRenamed event (whatever it's actually called) - pseudocode:
class ItemRenameCommand : IUndoableCommand {
string oldname, newname;
INamedModel Model { get; set; }ItemRenameCommand(INamedModel model, string oldname, string newname) {
this.oldname = oldname; this.newname = newname;
Model = model;
}void Undo() { Model.Name = oldname; }
void Redo() { Model.Name = newname; }
}class MainForm : Form {
...
void TreeNodeRenamed(object sender, NodeRenameEventArgs e){
IUndoableCommand renameCommand = new ItemRenameCommand(treeViewModel, e.OldName, e.NewName);
undoStack.Push(renameCommand);
}Stack<IUndoableCommand> undoStack, redoStack;
}(Remember, pseudocode; I can't remember how you actually hook onto the rename event of a TreeView, and it's not really the main point of the discussion, but it means that won't compile.) INamedModel is just for the Name property, you'd typically have all your view model classes implement something like that in a strongly typed environment. One can have an argument about whether the undo/redo stacks should be in the UI (i.e. the view) or the view-model, taking a MVVM approach to structure. I tend to feel that because it represents user actions, it is part of the view. Then, to undo, you take items off the undo stack and call .Undo() on each of them in turn, pushing them onto the redo stack. And to redo, you take items off the redo stack, move them to the undo stack and call .Redo() on each one. The tricky bit is making sure that everything can be represented by a reversible command. For some things (simplistic example, a Reset or Randomise button) you will have to store most or all of the previous state, but avoid doing that in all cases where it is possible to do so, as storing the whole state for each undo entry is a
Hi Bob, This is a great answer, thanks, and, imho, far more than this as-yet-non-responsive questioner deserves, or can probably "handle." But, I do feel that if the OP wants to implement Undo for just the Text displayed on TreeNodes, that's okay. People new to the game often need to start at a lower level of abstraction, and solving specific problems may, perhaps, lead them, later, to be able to have a "basis" for understanding higher-level abstractions and code strategies. If the OP shows any response, I'll help he or she with a simple example of Undo with the TreeNode text. best, Bill
"Beauty is in the eye of the beholder, and it may be necessary from time to time to give a stupid or misinformed beholder a black eye." Miss Piggy"
-
You shouldn't 'implement the Undo Functionality for rename'. You should implement undo as an app-wide thing which maintains a stack of commands across the whole application and knows how to undo them. There's two ways to do undo: either you maintain the state before each operation, or you store each operation as a command which knows how to undo itself. In all but the simplest case you want to do the second way. You need to implement every action within your application as a command, where command means something like:
interface IUndoableCommand {
void Undo();
void Redo();
}In this case, assuming your tree view is bound to some view-model level property, you would hook the NodeRenamed event (whatever it's actually called) - pseudocode:
class ItemRenameCommand : IUndoableCommand {
string oldname, newname;
INamedModel Model { get; set; }ItemRenameCommand(INamedModel model, string oldname, string newname) {
this.oldname = oldname; this.newname = newname;
Model = model;
}void Undo() { Model.Name = oldname; }
void Redo() { Model.Name = newname; }
}class MainForm : Form {
...
void TreeNodeRenamed(object sender, NodeRenameEventArgs e){
IUndoableCommand renameCommand = new ItemRenameCommand(treeViewModel, e.OldName, e.NewName);
undoStack.Push(renameCommand);
}Stack<IUndoableCommand> undoStack, redoStack;
}(Remember, pseudocode; I can't remember how you actually hook onto the rename event of a TreeView, and it's not really the main point of the discussion, but it means that won't compile.) INamedModel is just for the Name property, you'd typically have all your view model classes implement something like that in a strongly typed environment. One can have an argument about whether the undo/redo stacks should be in the UI (i.e. the view) or the view-model, taking a MVVM approach to structure. I tend to feel that because it represents user actions, it is part of the view. Then, to undo, you take items off the undo stack and call .Undo() on each of them in turn, pushing them onto the redo stack. And to redo, you take items off the redo stack, move them to the undo stack and call .Redo() on each one. The tricky bit is making sure that everything can be represented by a reversible command. For some things (simplistic example, a Reset or Randomise button) you will have to store most or all of the previous state, but avoid doing that in all cases where it is possible to do so, as storing the whole state for each undo entry is a