Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
376 views
in Technique[技术] by (71.8m points)

winforms - How to implement 'undo' operation in .net windows application?

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...