I want to implement undo and redo of inkcanvas strokes.
I want to implement redo and undo that can operate multiple times in a row.
I don't know where is the problem with my code. Please help me.
My code is as follows:
xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<InkCanvas x:Name="inkCanvas"
Grid.Column="0" Grid.ColumnSpan="2"
Grid.Row="0" Grid.RowSpan="7"
Width="Auto" Height="Auto" EditingMode="Ink"
IsHitTestVisible="True"
Background="LightSeaGreen"
UseCustomCursor="True"
Cursor="Pen"/>
<Button x:Name="btn_Test1"
Grid.Row="0"
Grid.Column="1"
Width="100"
Height="50"
Content="pen"
Cursor="Hand"
Tag="Test1"
Click="Button_Click" />
<Button x:Name="btn_Test3"
Grid.Row="1"
Grid.Column="1"
Width="100"
Height="50"
Content="clear"
Tag="Test3"
Click="Button_Click" />
<Button x:Name="btn_Test4"
Grid.Row="2"
Grid.Column="1"
Width="100"
Height="50"
Content="UnDo"
Tag="Undo"
Click="Button_Click" />
<Button x:Name="btn_Test5"
Grid.Row="3"
Grid.Column="1"
Width="100"
Height="50"
Content="ReDo"
Tag="Redo"
Click="Button_Click" />
</Grid>
code behind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media;
namespace InkCanvasUndoRedo
{
public partial class MainWindow : Window
{
public Stack<DoStroke> DoStrokes { get; set; }
public Stack<DoStroke> UndoStrokes { get; set; }
private bool handle = true;
public MainWindow()
{
InitializeComponent();
DoStrokes = new Stack<DoStroke>();
UndoStrokes = new Stack<DoStroke>();
inkCanvas.DefaultDrawingAttributes.FitToCurve = true;
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb(255, 255, 255, 255);
inkCanvas.Strokes.StrokesChanged = Strokes_StrokesChanged;
}
private void Strokes_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
{
if (handle)
{
DoStrokes.Push(new DoStroke
{
ActionFlag = e.Added.Count > 0 ? "ADD" : "REMOVE",
Stroke = e.Added.Count > 0 ? e.Added[0] : e.Removed[0]
});
}
}
public void Undo()
{
handle = false;
if (DoStrokes.Count > 0)
{
DoStroke dos = DoStrokes.Pop();
if (dos.ActionFlag.Equals("ADD"))
{
inkCanvas.Strokes.Remove(dos.Stroke);
}
else
{
inkCanvas.Strokes.Add(dos.Stroke);
}
UndoStrokes.Push(dos);
}
handle = true;
}
public void Redo()
{
handle = false;
if (UndoStrokes.Count > 0)
{
DoStroke dos = UndoStrokes.Pop();
if (dos.ActionFlag.Equals("ADD"))
{
inkCanvas.Strokes.Add(dos.Stroke);
}
else
{
inkCanvas.Strokes.Remove(dos.Stroke);
}
}
handle = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
switch ((sender as Button).Tag)
{
case "Test1":
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
break;
case "Test3":
inkCanvas.Strokes.Clear();
break;
case "Undo":
Undo();
break;
case "Redo":
Redo();
break;
}
}
}
public struct DoStroke
{
public string ActionFlag { get; set; }
public Stroke Stroke { get; set; }
}
}
The result: Write: 123
Click: undo->undo->redo->redo->undo
Expected: 3 disappear
CodePudding user response:
In your redo Method you do
DoStroke dos = UndoStrokes.Pop();
if (dos.ActionFlag.Equals("ADD"))
{
inkCanvas.Strokes.Add(dos.Stroke);
}
else
{
inkCanvas.Strokes.Remove(dos.Stroke);
}
You should probably call DoStrokes.Push(dos);
at the end of this. In a similar way as is done in the Undo-method.