Undo
Undoバッファのインターフェイスなクラス。
UndoBufferTargetはUndoBufferがビューの状態を操作する際の仲介役。
/// <summary> /// アンドゥバッファ基本クラス /// </summary> public abstract class UndoBuffer { /// <summary> /// 子 /// </summary> /// <remarks> /// 最後に入力した状態がリストの先頭になる。 /// </remarks> protected List<UndoBuffer> list = new List<UndoBuffer>(); /// <summary> /// アンドゥ /// </summary> public abstract void undo(); /// <summary> /// リドゥ /// </summary> public abstract void redo(); /// <summary> /// 子の追加 /// </summary> /// <param name="buffer">子</param> public virtual void add(UndoBuffer buffer){list.Insert(0,buffer);} } /// <summary> /// アンドゥバッファ操作対象オブジェクト /// </summary> public abstract class UndoBufferTarget { protected Object last_val = null; protected Object cur_val = null; public Object getLastValue() { return last_val; } public Object getCurrentValue() { return cur_val; } public virtual void setLastValue(Object value) { last_val = value; } public virtual void setCurrentValue(Object value) { cur_val = value; } }UndoBuffer実装クラス。
/// <summary> /// アンドゥバッファコンテナ /// </summary> public class UndoBufferContainer : UndoBuffer { /// <summary> /// 現在のバッファ位置 /// </summary> /// <remarks> /// 0〜バッファ数+1 /// </remarks> private int cur_idx = 0; /// <summary> /// アンドゥ /// </summary> public override void undo() { if(cur_idx != list.Count) list[cur_idx].undo(); cur_idx = Math.Min(cur_idx + 1, list.Count); } /// <summary> /// リドゥ /// </summary> public override void redo() { cur_idx = Math.Max(cur_idx - 1, 0); list[cur_idx].redo(); } } /// <summary> /// アンドゥバッファアイテム /// </summary> public class UndoBufferItem : UndoBuffer { private UndoBufferTarget target = null; private Object old_val = null; private Object new_val = null; /// <summary> /// コンストラクタ /// </summary> /// <param name="target">ターゲット</param> /// <param name="old_val">現在値</param> /// <param name="new_val">更新値</param> public UndoBufferItem(UndoBufferTarget target, Object old_val, Object new_val) { this.target = target; this.old_val = old_val; this.new_val = new_val; } /// <summary> /// アンドゥ /// </summary> public override void undo() { if (list.Count > 0) { for (int i = list.Count - 1; i >= 0; i--) list[i].undo(); } target.setCurrentValue(old_val); } /// <summary> /// リドゥ /// </summary> public override void redo() { if (list.Count > 0) { for (int i = list.Count - 1; i >= 0; i--) list[i].redo(); } target.setCurrentValue(new_val); } }UndoBufferTargetの実装クラス。UndoBuffer<->コントロールを仲介する。
/// <summary> /// UndoBufferTarget(コントロールをターゲット) /// </summary> public class UndoBufferTargetForControl : UndoBufferTarget { private System.Windows.Forms.Control target = null; /// <summary> /// コンストラクタ /// </summary> /// <param name="target">ターゲット</param> public UndoBufferTargetForControl(System.Windows.Forms.Control target) { this.target = target; last_val = this.target.Text; cur_val = this.target.Text; } /// <summary> /// 値のセット /// </summary> /// <param name="value">値</param> public override void setCurrentValue(Object value) { base.setCurrentValue(value); target.Text = value.ToString(); } }
動作確認用フォーム。
UndoBufferItemに子を追加することで一括操作が可能。
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private UndoBufferContainer undo_container = new UndoBufferContainer(); private UndoBufferItem macro_item = null; private bool is_rec = false; //マクロ記録中フラグ private void Form1_Load(object sender, EventArgs e) { textBox1.Tag = new UndoBufferTargetForControl(textBox1); textBox2.Tag = new UndoBufferTargetForControl(textBox2); textBox3.Tag = new UndoBufferTargetForControl(textBox3); textBox4.Tag = new UndoBufferTargetForControl(textBox4); textBox5.Tag = new UndoBufferTargetForControl(textBox5); } private void btnUndo_Click(object sender, EventArgs e) { undo_container.undo(); } private void btnRedo_Click(object sender, EventArgs e) { undo_container.redo(); } private void textBox_Leave(object sender, EventArgs e) { TextBox chg_obj = (TextBox)sender; UndoBufferTarget target = (UndoBufferTarget)chg_obj.Tag; if (is_rec) { if (macro_item == null) macro_item = new UndoBufferItem(target, target.getLastValue(), chg_obj.Text); else macro_item.add(new UndoBufferItem(target, target.getLastValue(), chg_obj.Text)); } else { undo_container.add(new UndoBufferItem(target, target.getLastValue(), chg_obj.Text)); } target.setLastValue(chg_obj.Text); } private void btnStMacro_Click(object sender, EventArgs e) { is_rec = true; } private void btnEdMacro_Click(object sender, EventArgs e) { if (macro_item != null) undo_container.add(macro_item); macro_item = null; is_rec = false; } }