views:

1168

answers:

10

Assume that, a win form has certain input fields and user enters/re-enters some data.

How to retain data previously entered by 'undo' operation?

Just I want to know the best way to accomplish it.

A: 

Depends on how many levels of undo, you wish to have.

You could store values before it is "committed" in some sense into a Form level collection for each of the controls, which you can "Restore" on click of a button for user to go back.

shahkalpesh
+2  A: 

I'm not sure if WinForms/.Net has some type of built-in Undo feature that you can take advantage of. But what you are really looking for is a Stack datastructure to help you manage a list of actions. You'll need to create some type of "action" object to represent the actions that a user could do and as they progress through the application you'll need to push these actions onto the Stack. When they hit the undo button, or Ctrl-Z or whatever method of initiating the undo action you'll pop off the current action and restore the application state to the previous action.

This is a very basic and high level overview of how this would work but I imagine that implementing such a feature can get quite complex. Just imagine how it needs to work for a program like Adobe Photoshop. :O

Ralph
+1  A: 

This and this might help.

JP Alioto
+1  A: 

CTRL + Z works on individual controls.

If you work with data and a BindingSource, you can "undo" the not persisted changes to the record(s) by calling the CancelEdit function or alternatively you can reload the data for the database.

dampee
+10  A: 

There are a few options. The important thing is that you start designing it in early in the project. Trying to add it to an existing project can be very expensive if it wasn't designed with this capability in mind.

There are a few fundamental patterns that you'll want to take advantage of:

  1. MVC or Observer pattern. The first key isn't so much the religious or pattern-zealot implementation of your high-level architecture. What is important is that your software recognizes the difference between its current state and the displayed state, and decouples appropriately. There needs to be a common, clearly-defined coupling between your visual state and your application state. This provides you with the common architecture you need to create a command (see #2).

  2. The Command pattern. You get a lot of quality with the command pattern (though it can come at the cost of some code that looks like it should be wizard-generated). The specific approach you take to the command pattern may vary (one class per command with implementation via overrides versus one class per many commands with implementation via event handlers, e.g.), but commands are the "action" class that @Ralph suggested structuring a stack around.

    This can be a bit tricky, but the general approach would be to listen for an event that would "commit" data from the visual state to the app state. The Validated event might be a good hook for a Textbox. The Click event would make more sense for a Button. When that commit happens, you create the command associated with that control, you attempt to execute the command, and you add the command to your undo stack if the command completes successfully. Now you're tracking exactly what's happening and exactly the data it's happening with.

  3. The Memento pattern. @JP Pulled out the last piece of the puzzle. You can use a memento on the saved command to store what the affected control's state was before the command executed. This, combined with an UnExecute() member on your command's interface, should be the last core piece of design you need to perform your task.

The nice thing about a structured approach like this is that you now have a natural extension point for additional behavior that needs to happen on a command-basis. Transactions are a natural fit, for example. In my current project, I'm using the WPF ICommand interface (in my winforms project) to provide feedback about whether a given command CanExecute() at any given time. This lets me enable and disable UI widgets appropriately in a purely command-driven way. :)

The unfortunate thing is that there isn't a lot of support for this structure built-in to Winforms (as far as I know), so you'll need to build most of it from scratch. No single piece is particularly complicated, but you can find yourself generating a fair amount of mostly-boilerplate code for each command. It's also a pervasive design technique. For it to be effective, it has to be used consistently throughout the appropriate portions of the application. This makes retrofitting the functionality pretty expensive, especially if the original code is tightly coupled and incohesive.

Greg D
I'm obviously glossing over some details here for the sake of space, but I think all the important pieces are there. :)
Greg D
A: 

This might not be the best way to go about it depending on what you're trying to accomplish, but you could use a richtextbox and call upon the undo method built into that control.

For example:

richTextBox1.Undo();
transmogrify
+1  A: 

My suggestion is to determine the specific undo requirements and its practical benefits before starting the design and implementation. I inherited a WinForms app that used a multiple operation sequential undo via a stack of generic "action" objects internally. However, it turned out that none of the users of the app I spoke with use nor requested the feature! And the way this particular app works, if I was a user of the app, I just would not see myself using the feature either.

The Undo functionality could have been more useful in this case if it was a 'selective' undo; where the user could select any single operation/edit of several previous edits made, prior to data commit, and restore that single edit to its original state, instead of only being able to undo the last operation first, followed by the second to last operation, etc. which is how it was implemented.

In any case, the app thus contains unneeded complexity and indirection, making it harder and slower to 'grok' and make changes and enhancements to existing functionality, in this case for little or no real-world benefit. Since I inherited the project, I have implemented new features without undo and nobody has had any complaints.

PaulR
+1  A: 

You may also found the Reversi library useful, as several others seems to have. See [http://www.codeproject.com/KB/dotnet/reversibleundoredo.aspx][1] or [this][2]

[1]: http://www.codeproject.com/KB/dotnet/reversibleundoredo.aspx Make Your Application Reversible to Support Undo And Redo

[2]: http://www.codeproject.com/script/Articles/Article.aspx?aid=22502 Undo Redo

A: 

The DLL at www.undomadeeasy.com might be the answer. It does all the hard work.

Carl Warman