步骤6
在你应用程序每次操作后,调用UndoRedo类的SetStateForUndoRedo()方法来使Undo Redo操作可用。
示例应用程序描述
这个示范WPF绘制应用程序用来作为结合Undo/Redo操作的案例。该WPF应用程序示例支持四种操作:插入对象、删除对象、移动对象和调整对象的尺寸,它还有两种类型的几何对象:矩形和多边形。它使用画布作为包含这些几何对象的容器。
现在,在此系列文章中,我们可以看到如何让这四个操作支持Undo/Redo。在第一部分,使用单个对象表示变化的方法实现。在第二部分,使用命令模式实现而在第三部分,使用备忘录模式实现。
使用备忘录模式实现示例应用程序的Undo/Redo
步骤1
这里的容器是包含Uielement对象的画布,而在不同操作期间,容器没有属性发生改变。
步骤2
现在,我们将使下面的memento类包含Uielement对象作为画布的状态。
Collapse Copy Code
public class Memento
{
private List<UIElement> _ContainerState;
public List<UIElement> ContainerState
{
get { return _ContainerState; }
}
public Memento(List<UIElement> containerState)
{
this._ContainerState = containerState;
}
}
public class Memento
{
private List<UIElement> _ContainerState;
public List<UIElement> ContainerState
{
get { return _ContainerState; }
}
public Memento(List<UIElement> containerState)
{
this._ContainerState = containerState;
}
}
现在这个备忘录代表了画布的状态。
步骤3
接下来的MementoOriginator利用深度拷贝画布的对象创建其备忘录并将备忘录设置给画布。
Collapse Copy Code
public class MementoOriginator
{
private Canvas _Container;
public MementoOriginator(Canvas container)
{
_Container = container;
}
public Memento getMemento()
{
List<UIElement> _ContainerState = new List<UIElement>();
foreach (UIElement item in _Container.Children)
{
if (!(item is Thumb))
{
UIElement newItem = DeepClone(item);
_ContainerState.Add(newItem);
}
}
return new Memento(_ContainerState);
}
public void setMemento(Memento memento)
{
_Container.Children.Clear();
Memento memento1 = MementoClone(memento);
foreach (UIElement item in memento1.ContainerState)
{
((Shape)item).Stroke = System.Windows.Media.Brushes.Black;
_Container.Children.Add(item);
}
}
public Memento MementoClone(Memento memento)
{
List<UIElement> _ContainerState = new List<UIElement>();
foreach (UIElement item in memento.ContainerState)
{
if (!(item is Thumb))
{
UIElement newItem = DeepClone(item);
_ContainerState.Add(newItem);
}
}
return new Memento(_ContainerState);
}
private UIElement DeepClone(UIElement element)
{
string shapestring = XamlWriter.Save(element);
StringReader stringReader = new StringReader(shapestring);
XmlTextReader xmlTextReader = new XmlTextReader(stringReader);
UIElement DeepCopyobject = (UIElement)XamlReader.Load(xmlTextReader);
return DeepCopyobject;
}
}
public class MementoOriginator
{
private Canvas _Container;
public MementoOriginator(Canvas container)
{
_Container = container;
}
public Memento getMemento()
{
List<UIElement> _ContainerState = new List<UIElement>();
foreach (UIElement item in _Container.Children)
{
if (!(item is Thumb))
{
UIElement newItem = DeepClone(item);
_ContainerState.Add(newItem);
}
}
return new Memento(_ContainerState);
}
public void setMemento(Memento memento)
{
_Container.Children.Clear();
Memento memento1 = MementoClone(memento);
foreach (UIElement item in memento1.ContainerState)
{
((Shape)item).Stroke = System.Windows.Media.Brushes.Black;
_Container.Children.Add(item);
}
}
public Memento MementoClone(Memento memento)
{
List<UIElement> _ContainerState = new List<UIElement>();
foreach (UIElement item in memento.ContainerState)
{
if (!(item is Thumb))
{
UIElement newItem = DeepClone(item);
_ContainerState.Add(newItem);
}
}
return new Memento(_ContainerState);
}
private UIElement DeepClone(UIElement element)
{
string shapestring = XamlWriter.Save(element);
StringReader stringReader = new StringReader(shapestring);
XmlTextReader xmlTextReader = new XmlTextReader(stringReader);
UIElement DeepCopyobject = (UIElement)XamlReader.Load(xmlTextReader);
return DeepCopyobject;
}
}
GetMemento() 方法深度拷贝画布的UIelement集合来创建一个备忘录并将其放回给调用方。SetMemento(Memento memento)方法首先清空画布然后通过将备忘录的每个对象添加给Canvas来设置备忘录。DeepClone(UIElement element)方法仅创建一个UIelement对象的深度拷贝。