如何在.NET Windows应用程序中实现“撤销”操作?

13
假设一个Windows窗体有一些输入字段,用户输入或重新输入了一些数据。
如何通过“撤销”操作保留先前输入的数据?
我想知道实现这个功能的最佳方法。
7个回答

18

有几个选择。重要的是您要在项目早期开始设计它。如果没有考虑到这种功能,试图将其添加到现有项目中可能会非常昂贵。

有几个基本模式可以利用:

  1. MVCObserver模式。第一个关键点不是你高级架构的宗教或模式狂热实现,而是你的软件识别其当前状态和显示状态之间的差异,并适当地解耦。需要在视觉状态和应用程序状态之间建立通用、清晰定义的耦合。这为你提供了创建命令所需的共同架构(参见#2)。

  2. Command模式。使用命令模式可以获得很多质量(虽然可能会以一些看起来应该由向导生成的代码为代价)。你采取的具体命令模式方法可能会有所不同(每个命令一个类,通过覆盖实现,或每个命令多个类,通过事件处理程序实现,例如),但命令是@Ralph建议围绕堆栈构建的“操作”类。

    这可能有点棘手,但一般的方法是监听一个事件,该事件将从视觉状态提交数据到应用程序状态。Validated事件可能是Textbox的好钩子。Click事件对于Button更有意义。当发生提交时,你创建与该控件相关联的命令,尝试执行命令,并将命令添加到撤消堆栈中,如果命令成功完成。现在你正在跟踪正在发生的事情以及它正在使用的数据。

  3. Memento模式。@JP提出了最后一块拼图。你可以在保存的命令上使用备忘录来存储命令执行前受影响控件的状态。这与你命令接口上的UnExecute()成员结合使用,应该是你需要执行任务的最后一个核心设计部分。

一个像这样的结构化方法的好处在于,您现在有了自然的扩展点,可以基于命令进行其他行为。例如,事务就是一个自然的选择。在我的当前项目中,我正在使用WPF ICommand 接口(在我的winforms项目中)来提供有关给定命令是否在任何给定时间CanExecute()的反馈。这让我以纯粹的命令驱动方式适当地启用和禁用UI小部件。 :)
不幸的是,在Winforms中并没有很多内置此结构的支持(据我所知),因此您需要从头开始构建大部分内容。没有一个单一的部分特别复杂,但是您可能会发现自己为每个命令生成相当多的大部分模板代码。它也是一种普遍的设计技术。为了有效,必须在应用程序的适当部分始终使用它。这使得后期添加功能非常昂贵,特别是如果原始代码紧密耦合且不连贯。

我显然为了篇幅而忽略了一些细节,但我认为所有重要的部分都在那里。 :) - Greg D

3
我不确定WinForms/.Net是否有一些内置的撤销功能可以利用。但你真正需要的是一个堆栈数据结构来帮助你管理操作列表。你需要创建某种“操作”对象来表示用户可能执行的操作,并在他们进入应用程序时将这些操作推到堆栈上。当他们按下撤销按钮,或者使用Ctrl-Z或其他启动撤销操作的方法时,你将弹出当前操作并将应用程序状态恢复到上一个操作。
这只是如何工作的一个非常基本和高级的概述,但我想实现这样的功能可能会变得非常复杂。想象一下像Adobe Photoshop这样的程序需要如何工作。:O

3

根据您想要达到的目标,这可能不是最好的方法,但您可以使用richtextbox并调用该控件内置的撤消方法。

例如:

richTextBox1.Undo();

2

CTRL + Z 可以在单个控件上使用。

如果您正在使用数据和 BindingSource,您可以通过调用 CancelEdit 函数来“撤消”未持久化的记录更改,或者您可以重新加载数据库中的数据。


1

1

我的建议是在开始设计和实现之前确定具体的撤消需求及其实际效益。我曾经接手过一个WinForms应用程序,它通过内部通用“操作”对象堆栈使用多次操作顺序撤消。然而,事实证明,我与该应用程序的所有用户都没有使用或请求此功能!而且这个特别的应用程序的工作方式,如果我是该应用程序的用户,我也不会看到自己使用此功能。

如果它是一种“选择性”撤消,那么在这种情况下,撤消功能可能会更有用;在数据提交之前,用户可以选择任何单个操作/编辑以还原该单个编辑到其原始状态,而不仅仅能够首先撤消上一个操作,然后是倒数第二个操作等等,这就是它的实现方式。

无论如何,该应用程序因此包含不必要的复杂性和间接性,使得对现有功能进行修改和增强变得更加困难和缓慢,而实际上并没有或几乎没有真正的世界效益。自从我接手这个项目以来,我已经实现了新的功能,没有撤消,也没有人抱怨过。


0

这取决于您希望拥有多少级撤销。

您可以在提交之前将值存储到某种程度上的表单级集合中,以便为每个控件进行“还原”,用户可以在单击按钮时返回。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接