Example Of UndoRedoManager V1_0_0 WPF C#
According to my previous post, today I will give you an example of UndoRedoManager API. In this post, I created little WPF form. You can follow code from MainWindow.xaml And MainWindow.xaml.cs.
MainWindow.xaml
In MainWindow.xaml, I designed simple form that you can see in example. Here is Canvas2D which contain a rectangle with some default style (color, size, transformation). Where at right side of the canvas, I created some textbox(es) and label(s) as propeties for rectangle manupulation. These properties are...
- X
- Y
- Width
- Height
- Rotation
- Fill R (Red)
- Fill G (Green)
- Fill B (Blue)
- Fill A (Alpha OR Transparent OR Opacity)
- Stroke R (Red)
- Stroke G (Green)
- Stroke B (Blue)
- Stroke A (Alpha OR Transparent OR Opacity)
- Stroke Width (Thickness)
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Saatody" x:Class="Saatody.MainWindow" Title="Saatody UndoRedoExperiment" Height="700" Width="800" ResizeMode="NoResize" WindowStartupLocation="CenterScreen"> <Grid Background="#1F1F1F"> <Grid.ColumnDefinitions> <ColumnDefinition Width="3*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="2*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Canvas Name="CanvasContainer" Grid.Column="0" Grid.Row="0" Background="#111111"> <Canvas Name="Canvas2D" Grid.Column="0" Grid.Row="0" Background="#111111"> <Rectangle Name="Rectangle" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0" Width="100" Height="200" Fill="#FFFFA500" Stroke="#FFFFFFFF" StrokeThickness="5"> <Rectangle.LayoutTransform> <RotateTransform Angle="0"/> </Rectangle.LayoutTransform> </Rectangle> </Canvas> </Canvas> <ScrollViewer Grid.Column="1" Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <Grid Name="Properties"> <Grid.Resources> <Style TargetType="Label"> <Setter Property="Foreground" Value="#FFFFFF"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="HorizontalAlignment" Value="Stretch"/> <Setter Property="VerticalAlignment" Value="Stretch"/> <Setter Property="HorizontalContentAlignment" Value="Left"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Margin" Value="10 5 5 5"/> </Style> <Style TargetType="TextBox"> <Setter Property="Foreground" Value="#FFFFFF"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="HorizontalAlignment" Value="Stretch"/> <Setter Property="VerticalAlignment" Value="Stretch"/> <Setter Property="HorizontalContentAlignment" Value="Left"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Margin" Value="5 5 10 5"/> </Style> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> <RowDefinition Height="35"/> </Grid.RowDefinitions> <Label Content="X:" Grid.Column="0" Grid.Row="0"/> <Label Content="Y:" Grid.Column="0" Grid.Row="1"/> <Label Content="Width:" Grid.Column="0" Grid.Row="2"/> <Label Content="Height:" Grid.Column="0" Grid.Row="3"/> <Label Content="Rotation:" Grid.Column="0" Grid.Row="4"/> <Label Content="Fill R:" Grid.Column="0" Grid.Row="5"/> <Label Content="Fill G:" Grid.Column="0" Grid.Row="6"/> <Label Content="Fill B:" Grid.Column="0" Grid.Row="7"/> <Label Content="Fill A:" Grid.Column="0" Grid.Row="8"/> <Label Content="Stroke R:" Grid.Column="0" Grid.Row="9"/> <Label Content="Stroke G:" Grid.Column="0" Grid.Row="10"/> <Label Content="Stroke B:" Grid.Column="0" Grid.Row="11"/> <Label Content="Stroke A:" Grid.Column="0" Grid.Row="12"/> <Label Content="Stroke Width:" Grid.Column="0" Grid.Row="13"/> <TextBox Name="X" Grid.Column="1" Grid.Row="0" Text="0" /> <TextBox Name="Y" Grid.Column="1" Grid.Row="1" Text="0" /> <TextBox Name="Width" Grid.Column="1" Grid.Row="2" Text="100" /> <TextBox Name="Height" Grid.Column="1" Grid.Row="3" Text="200" /> <TextBox Name="Rotation" Grid.Column="1" Grid.Row="4" Text="0" /> <TextBox Name="FillR" Grid.Column="1" Grid.Row="5" Text="255" /> <TextBox Name="FillG" Grid.Column="1" Grid.Row="6" Text="165" /> <TextBox Name="FillB" Grid.Column="1" Grid.Row="7" Text="0" /> <TextBox Name="FillA" Grid.Column="1" Grid.Row="8" Text="255" /> <TextBox Name="StrokeR" Grid.Column="1" Grid.Row="9" Text="255" /> <TextBox Name="StrokeG" Grid.Column="1" Grid.Row="10" Text="255" /> <TextBox Name="StrokeB" Grid.Column="1" Grid.Row="11" Text="255" /> <TextBox Name="StrokeA" Grid.Column="1" Grid.Row="12" Text="255" /> <TextBox Name="StrokeWidth" Grid.Column="1" Grid.Row="13" Text="5" /> </Grid> </ScrollViewer> <ScrollViewer Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <TextBox Name="Console" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" Foreground="Lime" Background="Transparent"/> </ScrollViewer> </Grid> </Window>
MainWindow.xaml.cs
You can see the below code for MainWindow.xaml.cs. You can very huge code right? But no, actually not huge. I created seperate events for all textbox(es). But really the coding is same for textbox(es). There are three common events for all textbox(es).
- PreviewTextInput
- LostKeyboardFocus
- PreviewKeyUp
PreviewTextInput
I used this event because of i need to check if enter character is number or not. so created these event for all textbox(es). There are all textbox(es) must contain numbers. So this event used for make strong validation.
LostKeyboardFocus
This event used for store stage (scene) of Rectangle in memory. These all stage store as xaml form. And also i used these event for stroke validations. For example: Rotation must contain 0 to 360 value. Color channel must contain 0 to 255 value. And the after lost focus from textbox the event will store stage in memory.
PreviewKeyUp
This event is also work as a LostKeyboardFocus event. These both used for same works. For examples: Validation just like RGB must contain 0 to 255 value and Rotation must contain 0 to 360 value. And after press and leave 'enter' button this event store stage (scene) in memory like LostKeyboardFocus event stores. But different is, LostKeyboardFocus event invoke while you leave focus on particular textbox when PreviewKeyUp event invoke while you press and leave 'enter' button.
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; namespace Saatody { public partial class MainWindow : Window { private UndoRedoManager URM = new UndoRedoManager(); public MainWindow() { InitializeComponent(); URM.Window = this; URM.RecordState(Rectangle); X.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (X.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; Y.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (Y.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; Width.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (Width.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; Height.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (Height.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; Rotation.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (Rotation.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; FillR.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (FillR.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; FillG.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (FillG.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; FillB.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (FillB.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; FillA.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (FillA.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; StrokeR.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (StrokeR.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; StrokeG.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (StrokeG.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; StrokeB.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (StrokeB.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; StrokeA.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (StrokeA.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; StrokeWidth.PreviewTextInput += (sender, e) => { string Ch = e.Text; if ((Ch != "0" && Ch != "1" && Ch != "2" && Ch != "3" && Ch != "4" && Ch != "5" && Ch != "6" && Ch != "7" && Ch != "8" && Ch != "9") || (StrokeWidth.Text.Length > 2)) { e.Handled = true; } else { e.Handled = false; } }; X.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(X.Text, out Number); if (!IsNumber) { X.Text = "" + 0; } UpdateRectangle(); }; Y.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(Y.Text, out Number); if (!IsNumber) { Y.Text = "" + 0; } UpdateRectangle(); }; Width.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(Width.Text, out Number); if (!IsNumber) { Width.Text = "" + 0; } UpdateRectangle(); }; Height.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(Height.Text, out Number); if (!IsNumber) { Height.Text = "" + 0; } UpdateRectangle(); }; Rotation.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(Rotation.Text, out Number); if (IsNumber) { if (Number > 360) { Rotation.Text = "" + 360; } } else { Rotation.Text = "" + 0; } UpdateRectangle(); }; FillR.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(FillR.Text, out Number); if (IsNumber) { if (Number > 255) { FillR.Text = "" + 255; } } else { FillR.Text = "" + 0; } UpdateRectangle(); }; FillG.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(FillG.Text, out Number); if (IsNumber) { if (Number > 255) { FillG.Text = "" + 255; } } else { FillG.Text = "" + 0; } UpdateRectangle(); }; FillB.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(FillB.Text, out Number); if (IsNumber) { if (Number > 255) { FillB.Text = "" + 255; } } else { FillB.Text = "" + 0; } UpdateRectangle(); }; FillA.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(FillA.Text, out Number); if (IsNumber) { if (Number > 255) { FillA.Text = "" + 255; } } else { FillA.Text = "" + 0; } UpdateRectangle(); }; StrokeR.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(StrokeR.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeR.Text = "" + 255; } } else { StrokeR.Text = "" + 0; } UpdateRectangle(); }; StrokeG.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(StrokeG.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeG.Text = "" + 255; } } else { StrokeG.Text = "" + 0; } UpdateRectangle(); }; StrokeB.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(StrokeB.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeB.Text = "" + 255; } } else { StrokeB.Text = "" + 0; } UpdateRectangle(); }; StrokeA.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(StrokeA.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeA.Text = "" + 255; } } else { StrokeA.Text = "" + 0; } UpdateRectangle(); }; StrokeWidth.LostKeyboardFocus += (sender, e) => { int Number; bool IsNumber = Int32.TryParse(StrokeWidth.Text, out Number); if (!IsNumber) { StrokeWidth.Text = "" + 0; } UpdateRectangle(); }; X.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(X.Text, out Number); if (!IsNumber) { X.Text = "" + 0; } UpdateRectangle(); } }; Y.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(Y.Text, out Number); if (!IsNumber) { Y.Text = "" + 0; } UpdateRectangle(); } }; Width.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(Width.Text, out Number); if (!IsNumber) { Width.Text = "" + 0; } UpdateRectangle(); } }; Height.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(Height.Text, out Number); if (!IsNumber) { Height.Text = "" + 0; } UpdateRectangle(); } }; Rotation.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(Rotation.Text, out Number); if (IsNumber) { if (Number > 360) { Rotation.Text = "" + 360; } } else { Rotation.Text = "" + 0; } UpdateRectangle(); } }; FillR.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(FillR.Text, out Number); if (IsNumber) { if (Number > 255) { FillR.Text = "" + 255; } } else { FillR.Text = "" + 0; } UpdateRectangle(); } }; FillG.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(FillG.Text, out Number); if (IsNumber) { if (Number > 255) { FillG.Text = "" + 255; } } else { FillG.Text = "" + 0; } UpdateRectangle(); } }; FillB.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(FillB.Text, out Number); if (IsNumber) { if (Number > 255) { FillB.Text = "" + 255; } } else { FillB.Text = "" + 0; } UpdateRectangle(); } }; FillA.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(FillA.Text, out Number); if (IsNumber) { if (Number > 255) { FillA.Text = "" + 255; } } else { FillA.Text = "" + 0; } UpdateRectangle(); } }; StrokeR.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(StrokeR.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeR.Text = "" + 255; } } else { StrokeR.Text = "" + 0; } UpdateRectangle(); } }; StrokeG.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(StrokeG.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeG.Text = "" + 255; } } else { StrokeG.Text = "" + 0; } UpdateRectangle(); } }; StrokeB.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(StrokeB.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeB.Text = "" + 255; } } else { StrokeB.Text = "" + 0; } UpdateRectangle(); } }; StrokeA.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(StrokeA.Text, out Number); if (IsNumber) { if (Number > 255) { StrokeA.Text = "" + 255; } } else { StrokeA.Text = "" + 0; } UpdateRectangle(); } }; StrokeWidth.PreviewKeyUp += (sender, e) => { if (e.Key == Key.Enter) { int Number; bool IsNumber = Int32.TryParse(StrokeWidth.Text, out Number); if (!IsNumber) { StrokeWidth.Text = "" + 0; } UpdateRectangle(); } }; this.KeyUp += (sender, e) => { if (e.Key == Key.Z) { // Undo Canvas2D.Children.Clear(); Rectangle = (Rectangle)URM.UndoState(); Canvas2D.Children.Add(Rectangle); UpdateProperties(); } else if (e.Key == Key.Y) { // Redo Canvas2D.Children.Clear(); Rectangle = (Rectangle)URM.RedoState(); Canvas2D.Children.Add(Rectangle); UpdateProperties(); } }; } public void UpdateRectangle() { int iX = Int32.Parse(X.Text); int iY = Int32.Parse(Y.Text); int iWidth = Int32.Parse(Width.Text); int iHeight = Int32.Parse(Height.Text); int iRotation = Int32.Parse(Rotation.Text); byte iFillR = Byte.Parse(FillR.Text); byte iFillG = Byte.Parse(FillG.Text); byte iFillB = Byte.Parse(FillB.Text); byte iFillA = Byte.Parse(FillA.Text); byte iStrokeR = Byte.Parse(StrokeR.Text); byte iStrokeG = Byte.Parse(StrokeG.Text); byte iStrokeB = Byte.Parse(StrokeB.Text); byte iStrokeA = Byte.Parse(StrokeA.Text); int iStrokeWidth = Int32.Parse(StrokeWidth.Text); Rectangle.Margin = new Thickness(iX, iY, 0, 0); Rectangle.Width = iWidth; Rectangle.Height = iHeight; Rectangle.LayoutTransform = new RotateTransform(iRotation); Rectangle.Fill = new SolidColorBrush(Color.FromArgb(iFillA, iFillR, iFillG, iFillB)); Rectangle.Stroke = new SolidColorBrush(Color.FromArgb(iStrokeA, iStrokeR, iStrokeG, iStrokeB)); Rectangle.StrokeThickness = iStrokeWidth; URM.RecordState(Rectangle); } public void UpdateProperties() { Color Fill = ((SolidColorBrush)Rectangle.Fill).Color; Color Stroke = ((SolidColorBrush)Rectangle.Stroke).Color; string iX = Rectangle.Margin.Left.ToString(); string iY = Rectangle.Margin.Top.ToString(); string iWidth = Rectangle.Width.ToString(); string iHeight = Rectangle.Height.ToString(); string iRotation = ((RotateTransform)Rectangle.LayoutTransform).Angle.ToString(); string iFillR = Fill.R.ToString(); string iFillG = Fill.G.ToString(); string iFillB = Fill.B.ToString(); string iFillA = Fill.A.ToString(); string iStrokeR = Stroke.R.ToString(); string iStrokeG = Stroke.G.ToString(); string iStrokeB = Stroke.B.ToString(); string iStrokeA = Stroke.A.ToString(); string iStrokeWidth = Rectangle.StrokeThickness.ToString(); X.Text = iX; Y.Text = iY; Width.Text = iWidth; Height.Text = iHeight; Rotation.Text = iRotation; FillR.Text = iFillR; FillG.Text = iFillG; FillB.Text = iFillB; FillA.Text = iFillA; StrokeR.Text = iStrokeR; StrokeG.Text = iStrokeG; StrokeB.Text = iStrokeB; StrokeA.Text = iStrokeA; StrokeWidth.Text = iStrokeWidth; } } }
UndoRedoManager.cs
Here UndoRedoManager.cs is your storage where all scene stores in xaml list memory. for more information about these class please go: Create UndoRedoManager V1_0_0 For WPF C#.
using System; using System.Collections.Generic; using System.IO; using System.Windows.Markup; using System.Xml; namespace Saatody { public class UndoRedoManager { public MainWindow Window { set; get; } private int Pointer = 0; private List<string> States = new List<string>(); public void RecordState(object State) { try { States.RemoveRange(Pointer + 1, States.Count - (Pointer + 1)); } catch(Exception Ex) { } States.Add(XamlWriter.Save(State)); Pointer = States.Count - 1; Window.Console.Text = "Record State (" + Pointer + "): " + XamlWriter.Save(State) + "\n" + Window.Console.Text; } public object UndoState() { if (Pointer > 0) { Pointer -= 1; } Window.Console.Text = "Undo State (" + Pointer + "): " + States[Pointer] + "\n" + Window.Console.Text; StringReader StringReader = new StringReader(States[Pointer]); XmlReader XmlReader = XmlReader.Create(StringReader); object State = (object)XamlReader.Load(XmlReader); StringReader.Close(); XmlReader.Close(); return State; } public object RedoState() { if (Pointer < (States.Count - 1)) { Pointer += 1; } Window.Console.Text = "Redo State (" + Pointer + "): " + States[Pointer] + "\n" + Window.Console.Text; StringReader StringReader = new StringReader(States[Pointer]); XmlReader XmlReader = XmlReader.Create(StringReader); object State = (object)XamlReader.Load(XmlReader); StringReader.Close(); XmlReader.Close(); return State; } } }
I hope you can use this feature for your software.
Comments
Post a Comment