今天我发现 FW 4.5 有自己的 undoredo 管理器(如果我没看错的话)http://msdn.microsoft.com/en-us/library/System.ComponentModel.Design.UndoEngine%28v=vs.110%29.aspx
好吧,我找不到任何关于如何开始使用这个类来简单地撤销/重做基于文本的控件的例子,我知道其他的替代方法来做可撤销的事情,但我只是想学习如何用这个。
当我尝试使用构造函数时,它有任何要传递的参数,而且 Intellisense 也没有向我显示 System.ComponentModel.Design.UndoEngine
类的任何方法,我真的不知道我不知道如何使用它。
有人可以用 C#
或 VBNET
的例子来说明我们的方法吗? (如果可能的话,我更喜欢 VBNET 文档)
最佳答案
UndoEngine 是一个抽象类,Visual Studio 和 Designers 以他们自己的方式实现了 UndoEngine,并且这些必须是私有(private)的或不可用于再分发。你将无法使用它,实际上抽象类只是一个接口(interface),几乎没有实现,它根本不是一个撤销框架。
您仍然需要编写自己的撤消管理,但是从 UndoEngine 类派生撤消引擎的好处是,它可以很容易地托管/与 VS 和其他基于 MS 的编辑器集成。
- 如果你想在 Visual Studio 文档编辑器中提供编辑体验,那么你必须从 UndoEngine 派生你的 Undo 框架类,VS 会自动突出显示禁用撤消/重做按钮,并调用你的类的撤消/重做方法。
- 如果你想在自己的应用程序中使用 UndoEngine,UndoEngine 不会帮你做任何事情,你必须自己编写每个功能。 UndoEngine 只是管理 Undo/Redo 堆栈,真正的工作在 UndoUnit 内部。它基于工作单元概念,您的每个操作实际上都应该代表一项可以撤消的工作。
最简单的UndoEngine实现
假设您正在更改一个全局变量,
// following code uses big UndoUnit
public void SetGlobalVariable(object v){
var oldValue = GlobalVariable;
GlobalVariable = v;
var action = new UndoUnit{
UndoAction = ()=>{
GlobalVariable = oldValue;
},
RedoAction = ()=>{
GlobalVariable = v;
}
};
UndoManager.Add(action);
}
/// <summary>
/// Used to indicates the designer's status
/// </summary>
public enum UndoUnitState
{
Undoing,
Redoing,
}
/// <summary>
/// A UndoUnitBase can be used as a IOleUndoUnit or just a undo step in
/// a transaction
/// </summary>
public class UndoUnitBase : IOleUndoUnit
{
public Action UndoAction {get;set;}
public Action RedoAction {get;set;}
private string name = null;
private Guid clsid = Guid.Empty;
private bool inDoAction = false;
private bool isStillAtTop = true;
private UndoUnitState unitState = UndoUnitState.Undoing;
protected UndoUnit UnitState
{
get { return unitState; }
set { unitState = value; }
}
/// <summary>
/// </summary>
/// <param name="undoManager"></param>
/// <param name="name"></param>
internal UndoUnitBase(string name)
{
this.name = name;
}
~UndoUnitBase()
{
}
/// <summary>
/// </summary>
protected bool InDoAction
{
get
{
return inDoAction;
}
}
public string UndoName
{
get
{
return name;
}
set
{
this.name = value;
}
}
public Guid Clsid
{
get { return clsid; }
set { clsid = value; }
}
/// <summary>
/// This property indicates whether the undo unit is at the top (most recently added to)
/// the undo stack. This is useful to know when deciding whether undo units for operations
/// like typing can be coallesced together.
/// </summary>
public bool IsStillAtTop
{
get { return isStillAtTop; }
}
/// <summary>
/// This function do the actual undo, and then revert the action to be a redo
/// </summary>
/// <returns>objects that should be selected after DoAction</returns>
protected abstract void DoActionInternal();
/// <devdoc>
/// IOleUndoManager's "Do" action.
/// </devdoc>
void IOleUndoUnit.Do(IOleUndoManager oleUndoManager)
{
Do(oleUndoManager);
}
protected virtual int Do(IOleUndoManager oleUndoManager)
{
try
{
if(unitState== UndoUnitState.Undoing){
UndoAction();
}else{
RedoAction();
}
unitState = (unitState == UndoUnitState.Undoing) ? UndoUnitState.Redoing : UndoUnitState.Undoing;
if (oleUndoManager != null)
oleUndoManager.Add(this);
return VSConstants.S_OK;
}
catch (COMException e)
{
return e.ErrorCode;
}
catch
{
return VSConstants.E_ABORT;
}
finally
{
}
}
/// <summary>
/// </summary>
/// <returns></returns>
void IOleUndoUnit.GetDescription(out string pBstr)
{
pBstr = name;
}
/// <summary>
/// </summary>
/// <param name="clsid"></param>
/// <param name="pID"></param>
/// <returns></returns>
void IOleUndoUnit.GetUnitType(out Guid pClsid, out int plID)
{
pClsid = Clsid;
plID = 0;
}
/// <summary>
/// </summary>
void IOleUndoUnit.OnNextAdd()
{
// We are no longer the top most undo unit; another one was added.
isStillAtTop = false;
}
}
public class MyUndoEngine : UndoEngine, IUndoHandler
{
Stack<UndoEngine.UndoUnit> undoStack = new Stack<UndoEngine.UndoUnit>();
Stack<UndoEngine.UndoUnit> redoStack = new Stack<UndoEngine.UndoUnit>();
public ReportDesignerUndoEngine(IServiceProvider provider) : base(provider)
{
}
#region IUndoHandler
public bool EnableUndo {
get {
return undoStack.Count > 0;
}
}
public bool EnableRedo {
get {
return redoStack.Count > 0;
}
}
public void Undo()
{
if (undoStack.Count > 0) {
UndoEngine.UndoUnit unit = undoStack.Pop();
unit.Undo();
redoStack.Push(unit);
}
}
public void Redo()
{
if (redoStack.Count > 0) {
UndoEngine.UndoUnit unit = redoStack.Pop();
unit.Undo();
undoStack.Push(unit);
}
}
#endregion
protected override void AddUndoUnit(UndoEngine.UndoUnit unit)
{
undoStack.Push(unit);
}
}
关于c# - 如何开始使用 .NET Framework UndoEngine 类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20149115/