いらないノードを削除するまえにゴミ箱に移動するようにしましょう。
そのためにはゴミ箱の役割をするノードをつくる必要があります。最上位のレベルで一番下の位置につくることにします。
わかりやすくするためにプログラムがはじまったら、すぐにゴミ箱をつくります。
ただし、これはダメです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); group.SetTreeView(syncTreeViewEx1); group.SetTreeView(syncTreeViewEx2); Data data0 = new Data(); syncTreeViewEx1.AddNodeLastChild(null, "Root", 2, 2, data0); Data data1 = new Data(); syncTreeViewEx1.AddNodeLastChild(null, "ゴミ箱", 2, 2, data1); return; } } |
他のTreeViewと対応しているノードをみつけるためにノード作成時刻を利用しています。
2つのノードをつくる時刻がまったく同じになってしまうことが多いのです。100万分の1秒単位でも同じになってしまうのでちょっと驚いています。そこでSystem.Threading.Thread.Sleep(10)を入れます。これで時間をずらすことができます。
それからどれがゴミ箱なのか記憶しておく必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public partial class Form1 : Form { // ゴミ箱を覚えておく static TreeNodeEx _trashNode = null; public static TreeNodeEx TrashNode { get { return _trashNode; } } public Form1() { InitializeComponent(); Data data0 = new Data(); TreeNodeEx newTreeNodeEx = syncTreeViewEx1.AddNodeLastChild(null, "Root", 2, 2, data0); System.Threading.Thread.Sleep(10); Data data1 = new Data(); _trashNode = syncTreeViewEx1.AddNodeLastChild(null, "ゴミ箱", 2, 2, data1); System.Threading.Thread.Sleep(10); Data data2 = new Data(); syncTreeViewEx1.AddNodeLastChild(newTreeNodeEx, "New Node", 0, 0, data2); newTreeNodeEx.IsExpanded = true; } } |
このプログラムではRootノードの子ノードが見えるように展開しています。
それからもうひとつ気をつけることがあります。ファイルを読み込んだときにTreeNodeEx.Keyの値が変更されてしまうということです。
ゴミ箱の位置は、最上位のレベルで一番下の位置なので、ファイルを読み込んだときにゴミ箱の位置を調べて保存しなおしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public partial class Form1 : Form { private void openFileToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog open = new OpenFileDialog(); open.Filter = "trtファイル|*.trt"; if (open.ShowDialog() == DialogResult.OK) { StreamReader sr = new StreamReader(open.FileName); XmlSerializer xml = new XmlSerializer(typeof(Doc), types.ToArray()); var doc = (Doc)xml.Deserialize(sr); sr.Close(); syncTreeViewEx1.RestoreNodes(doc.treeNodeExes, null, InsertTo.LastChild); syncTreeViewEx1.SetExpands(null, doc.treeNodeExes.Select(x => x.IsExpanded).ToList()); curFilePath = open.FileName; _trashNode = syncTreeViewEx1.GetTopLevelLastTreeNodeEx(); // ここがゴミ箱の位置 } } } |
さてノードを削除するとき、いきなり削除するのではなく、ゴミ箱に移動させます。ゴミ箱の中にあるものが削除される場合はそのまま削除してしまいます。
そのノードが別のTreeViewでは選択されている(データが編集されている)可能性があります。そこで別のTreeViewでは選択されている場合は警告のメッセージボックスを表示することにしました。
またそれでも削除をする場合、削除されたノードが選択されていたTreeViewでは別の適切なノードを選択させる必要があります。
まず、対象のノードがゴミ箱のなかにあるかどうかを知るには最上位レベルのノードのKeyを調べて、最初に保存しているtrashKeyと同じかどうかを調べればいいですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class SyncTreeViewEx : SyncTreeView { public bool IsInTrash(TreeNodeEx targetNode) { TreeNodeEx temp = targetNode; while (temp != null) { if (temp == Form1.TrashNode) return true; temp = temp.ParentNode; } return false; } } |
次にノードを削除(またはゴミ箱に移動)することになるのですが、ゴミ箱に入れた場合、削除されるノードを選択していたTreeViewはどのノードを選択すればよいのでしょうか?
削除されるノードに次のノードがあるのであれば次のノードを、なければ前のノードを、それもなければ親ノードを選択するようにしています。次、前、親、いずれも存在しない場合はノード削除はできないようにしています。
またゴミ箱ノードそのものを削除しようとしたときは、ゴミ箱は削除しないで中身のみを削除(TrashClearメソッド)するようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class SyncTreeViewEx : SyncTreeView { private void DeleteNodeToolStripMenuItem_Click(object sender, EventArgs e) { TreeNodeEx nodeEx = syncTreeViewEx1.SelectedNode; DeteleNodes(nodeEx); } void DeteleNodes(TreeNodeEx targetNode) { if (TrashNode == targetNode) TrashClear(); else DeteleNodes0(targetNode); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
public class SyncTreeViewEx : SyncTreeView { void DeteleNodes0(TreeNodeEx targetNode) { var deleteNode = targetNode; TreeNodeEx nextSelectNode = null; if (deleteNode.NextNode != null) nextSelectNode = deleteNode.NextNode; else if (deleteNode.PrevNode != null) nextSelectNode = deleteNode.PrevNode; else if (deleteNode.ParentNode != null) nextSelectNode = deleteNode.ParentNode; else return; var deletingNode = syncTreeViewEx1.GetTreeNodeExs(targetNode); List<SyncTreeViewEx> syncTreeViewEx = new List<SyncTreeViewEx>(); foreach (SyncTreeViewEx views in syncTreeViewEx1.SyncTreeViews) { if (views.SelectedNode == null) continue; if (deletingNode.Any(x => x == views.SelectedNode)) syncTreeViewEx.Add(views); } if (syncTreeViewEx.Count > 1) { var dr = MessageBox.Show("別のTreeViewで選択中のノードが削除されようとしています。削除しますか?", "", MessageBoxButtons.YesNo); if (dr == DialogResult.No) return; } foreach (var view in syncTreeViewEx) view.SelectedNode = nextSelectNode; if (syncTreeViewEx1.IsInTrash(targetNode)) syncTreeViewEx1.DeleteNode(targetNode); else syncTreeViewEx1.MoveToLastChild(targetNode, TrashNode); } void TrashClear() { TreeNodeEx nextSelectNode = TrashNode; var deletingNode = syncTreeViewEx1.GetTreeNodeExs(TrashNode); deletingNode.Remove(TrashNode); List<SyncTreeViewEx> syncTreeViewEx = new List<SyncTreeViewEx>(); foreach (SyncTreeViewEx views in syncTreeViewEx1.SyncTreeViews) { if (views.SelectedNode == null) continue; if (deletingNode.Any(x => x == views.SelectedNode)) syncTreeViewEx.Add(views); } if (syncTreeViewEx.Count > 0) { var dr = MessageBox.Show("別のTreeViewで選択中のノードが削除されようとしています。削除しますか?", "", MessageBoxButtons.YesNo); if (dr == DialogResult.No) return; } foreach (var view in syncTreeViewEx) { if (view.IsInTrash(view.SelectedNode)) view.SelectedNode = nextSelectNode; } while (TrashNode.FirstNode != null) syncTreeViewEx1.DeleteNode(TrashNode.FirstNode); } } |
ゴミ箱ノードは最上位のレベルで一番下の位置から動くことはありません。そこでゴミ箱をドラッグしたり、移動させることはできないようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class SyncTreeViewEx : SyncTreeView { protected override void OnBeginItemDrag(BeginItemDragArgs e) { if (Form1.TrashNode == e.DragNodeEx) { e.IsCancel = true; return; } Form1.ignoreSelectedNodeChange = true; base.OnBeginItemDrag(e); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
public partial class Form1 : Form { private void AddNextItemToolStripMenuItem_Click(object sender, EventArgs e) { TreeNodeEx node = syncTreeViewEx1.SelectedNode; if (Form1.TrashNode == node) return; syncTreeViewEx1.AddNodeNext(node, String.Format("NewItem {0}", ++num), 3, 3, new Data()); } private void MoveToPrevToolStripMenuItem_Click(object sender, EventArgs e) { TreeNodeEx node = syncTreeViewEx1.SelectedNode; if (Form1.TrashNode == node) return; ignoreSelectedNodeChange = true; syncTreeViewEx1.MoveToPrev(node); ignoreSelectedNodeChange = false; } private void LevelDownToolStripMenuItem_Click(object sender, EventArgs e) { TreeNodeEx node = syncTreeViewEx1.SelectedNode; if (Form1.TrashNode == node) return; ignoreSelectedNodeChange = true; syncTreeViewEx1.LevelDown(node); ignoreSelectedNodeChange = false; } private void MoveToNextToolStripMenuItem_Click(object sender, EventArgs e) { TreeNodeEx node = syncTreeViewEx1.SelectedNode; if (Form1.TrashNode.PrevNode == node) return; ignoreSelectedNodeChange = true; syncTreeViewEx1.MoveToNext(node); ignoreSelectedNodeChange = false; } private void PasteNextToolStripMenuItem_Click(object sender, EventArgs e) { TreeNodeEx node = syncTreeViewEx1.SelectedNode; if (Form1.TrashNode == node) return; syncTreeViewEx1.PasteFromClipboard(syncTreeViewEx1.SelectedNode, InsertTo.NextNode, types.ToArray()); } } |