using System; using System.Collections.Generic; using System.Windows; using System.Windows.Ink; using System.Windows.Input; // Added for UIElement namespace Ink_Canvas.Helpers { public partial class TimeMachine { private readonly List _currentStrokeHistory = new List(); private int _currentIndex = -1; public delegate void OnUndoStateChange(bool status); public event OnUndoStateChange OnUndoStateChanged; public delegate void OnRedoStateChange(bool status); public event OnRedoStateChange OnRedoStateChanged; public void CommitStrokeUserInputHistory(StrokeCollection stroke) { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } _currentStrokeHistory.Add(new TimeMachineHistory(stroke, TimeMachineHistoryType.UserInput, false)); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); } public void CommitStrokeShapeHistory(StrokeCollection strokeToBeReplaced, StrokeCollection generatedStroke) { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } _currentStrokeHistory.Add(new TimeMachineHistory(generatedStroke, TimeMachineHistoryType.ShapeRecognition, false, strokeToBeReplaced)); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); } public void CommitStrokeManipulationHistory(Dictionary> stylusPointDictionary) { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } _currentStrokeHistory.Add( new TimeMachineHistory(stylusPointDictionary, TimeMachineHistoryType.Manipulation)); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); } public void CommitStrokeDrawingAttributesHistory(Dictionary> drawingAttributes) { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } _currentStrokeHistory.Add( new TimeMachineHistory(drawingAttributes, TimeMachineHistoryType.DrawingAttributes)); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); } public void CommitStrokeEraseHistory(StrokeCollection stroke, StrokeCollection sourceStroke = null) { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } _currentStrokeHistory.Add(new TimeMachineHistory(stroke, TimeMachineHistoryType.Clear, true, sourceStroke)); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); } public void ClearStrokeHistory() { _currentStrokeHistory.Clear(); _currentIndex = -1; NotifyUndoRedoState(); } public TimeMachineHistory Undo() { if (_currentIndex < 0 || _currentIndex >= _currentStrokeHistory.Count) { return null; } var item = _currentStrokeHistory[_currentIndex]; item.StrokeHasBeenCleared = !item.StrokeHasBeenCleared; _currentIndex--; OnUndoStateChanged?.Invoke(_currentIndex > -1); OnRedoStateChanged?.Invoke(_currentStrokeHistory.Count - _currentIndex - 1 > 0); return item; } public TimeMachineHistory Redo() { if (_currentStrokeHistory.Count == 0 || _currentIndex >= _currentStrokeHistory.Count - 1) { return null; } var item = _currentStrokeHistory[++_currentIndex]; item.StrokeHasBeenCleared = !item.StrokeHasBeenCleared; NotifyUndoRedoState(); return item; } public TimeMachineHistory[] ExportTimeMachineHistory() { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } return _currentStrokeHistory.ToArray(); } public bool ImportTimeMachineHistory(TimeMachineHistory[] sourceHistory) { _currentStrokeHistory.Clear(); _currentStrokeHistory.AddRange(sourceHistory); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); return true; } private void NotifyUndoRedoState() { OnUndoStateChanged?.Invoke(_currentIndex > -1); OnRedoStateChanged?.Invoke(_currentStrokeHistory.Count - _currentIndex - 1 > 0); } /// 当前历史是否允许撤销。 public bool CanUndo => _currentIndex > -1; /// 当前历史是否允许重做。 public bool CanRedo => _currentStrokeHistory.Count > 0 && _currentStrokeHistory.Count - _currentIndex - 1 > 0; } public class TimeMachineHistory { public TimeMachineHistoryType CommitType; public bool StrokeHasBeenCleared; public StrokeCollection CurrentStroke; public StrokeCollection ReplacedStroke; //这里说一下 Tuple的 Value1 是初始值 ; Value 2 是改变值 public Dictionary> StylusPointDictionary; public Dictionary> DrawingAttributes; public UIElement InsertedElement; // 新增 public TimeMachineHistory(StrokeCollection currentStroke, TimeMachineHistoryType commitType, bool strokeHasBeenCleared) { CommitType = commitType; CurrentStroke = currentStroke; StrokeHasBeenCleared = strokeHasBeenCleared; ReplacedStroke = null; } public TimeMachineHistory(Dictionary> stylusPointDictionary, TimeMachineHistoryType commitType) { CommitType = commitType; StylusPointDictionary = stylusPointDictionary; } public TimeMachineHistory(Dictionary> drawingAttributes, TimeMachineHistoryType commitType) { CommitType = commitType; DrawingAttributes = drawingAttributes; } public TimeMachineHistory(StrokeCollection currentStroke, TimeMachineHistoryType commitType, bool strokeHasBeenCleared, StrokeCollection replacedStroke) { CommitType = commitType; CurrentStroke = currentStroke; StrokeHasBeenCleared = strokeHasBeenCleared; ReplacedStroke = replacedStroke; } public TimeMachineHistory(UIElement element, TimeMachineHistoryType commitType) // 新增 { CommitType = commitType; InsertedElement = element; } } public enum TimeMachineHistoryType { UserInput, ShapeRecognition, Clear, Manipulation, DrawingAttributes, ElementInsert // 新增 } public partial class TimeMachine // 新增partial,便于扩展 { public void CommitElementInsertHistory(UIElement element) { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } _currentStrokeHistory.Add(new TimeMachineHistory(element, TimeMachineHistoryType.ElementInsert)); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); } public void CommitElementRemoveHistory(UIElement element) { if (_currentIndex + 1 < _currentStrokeHistory.Count) { _currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex); } var history = new TimeMachineHistory(element, TimeMachineHistoryType.ElementInsert); history.StrokeHasBeenCleared = true; // 标记为已清除 _currentStrokeHistory.Add(history); _currentIndex = _currentStrokeHistory.Count - 1; NotifyUndoRedoState(); } } }