ツリービューを二つ作り、内容は同じにするプログラムをつくります。
アイテムを追加するだけなら簡単です。これは第一引数で指定したノードの子として新しいノードを追加する関数です。
1 2 3 4 |
void AddNode(TreeNode target, string newText) { target.Nodes.Add(newText); } |
さて、片方のビューにアイテムを追加したとき、もう片方に追加するにはどうすればいいでしょうか?
まず対応するアイテムを知る必要があります。そのためにはノードを追加したときに識別子になるものを用意すればよいのですが、以下の方法が考えられます。
TreeNodeのプロパティ Tagにデータをセットする
TreeNodeのプロパティ Nameにユニークな文字列をセットする
ここでは2つめの方法でやってみようと思います。
このようなクラスを作成しました。これを使えば簡単にできます。
SyncGroup.SetTreeViewでアイテムを同期するツリービューを登録しています。ここから同期対象のTreeViewとTreeNodeを探すようにします。またSyncGroup.SetTreeViewは同じものを2つ以上登録できないような仕組みにしています。
同期の対象になるコントロールを登録する
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 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); group = new SyncGroup(null); group.SetTreeView(syncTreeView1); group.SetTreeView(syncTreeView2); } SyncGroup group = null; } public class SyncGroup { public SyncGroup(ImageList list) { _imageList = list; } ImageList _imageList = null; List<TreeViewEx> _treeViews = new List<TreeViewEx>(); internal List<TreeViewEx> TreeViews { get { _treeViews = _treeViews.Where(x => !x.IsDisposed).ToList(); return _treeViews; } } public void SetTreeView(SyncTreeView treeView) { if (!TreeViews.Any(x => x == treeView.treeViewEx1)) { _treeViews.Add(treeView.treeViewEx1); treeView.treeViewEx1.ImageList = _imageList; if (treeView.treeViewEx1.group != null) treeView.treeViewEx1.group.RemoveTreeView(treeView); treeView.treeViewEx1.group = this; treeView.SyncGroup = this; } } } |
TreeNodeを追加する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form1 : Form { private void buttonAddLast_Click(object sender, EventArgs e) { // textBox1.Textの文字列を使用する。ない場合は"No Name"とする string newText = "No Name"; if (textBox1.Text != "") newText = textBox1.Text; var node = syncTreeView1.SelectedNode; syncTreeView1.AddNodeLastChild(node, newText, 0, 0, null); textBox1.Text = ""; } } |
TreeNodeを追加するためには同期の対象として登録したTreeViewから対応しているTreeNodeを見つける必要があります。これをやってくれるのがSyncTreeView.SelectedNodeプロパティです。
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 |
public partial class SyncTreeView : UserControl { public TreeNodeEx SelectedNode { get { return GetTreeNodeEx(treeViewEx1.SelectedNode); } } internal TreeNodeEx GetTreeNodeEx(TreeNode node) { if (node == null) return null; TreeNodeEx ex = new TreeNodeEx(this.SyncGroup); ex._text = node.Text; ex._level = node.Level; ex._key = node.Name; ex._toolTipText = node.ToolTipText; ex._backColorArgb = node.BackColor.ToArgb(); ex._checked = node.Checked; ex._foreColorArgb = node.ForeColor.ToArgb(); ex._imageIndex = node.ImageIndex; ex._isExpanded = node.IsExpanded; ex._selectedImageIndex = node.SelectedImageIndex; ex._data = node.Tag; return ex; } } |
対応するものが見つかったらTreeNodeを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public partial class SyncTreeView : UserControl { public void AddNodeLastChild(TreeNodeEx parentNode, string newText, int imageIndex, int selectedImageIndex, object data) { DateTime dt = DateTime.Now; string newKey = dt.Ticks.ToString(); foreach (TreeViewEx view in SyncGroup.TreeViews) { if (parentNode == null) { view.AddNodeLastChild(null, newKey, newText, imageIndex, selectedImageIndex, data); continue; } TreeNode[] nodes = view.Nodes.Find(parentNode.Key, true); if (nodes.Length > 0) view.AddNodeLastChild(nodes[0], newKey, newText, imageIndex, selectedImageIndex, data); } } } |
作成したTreeNodeのNameプロパティにユニークな文字列を追加する必要がありますが、時刻を利用しています。これなら他とダブる可能性はないと思います。
parentNodeがnullの場合は一番上の階層の一番最後に追加します。それ以外の場合はparentNodeのNameプロパティを調べて、同じものを探してその子アイテムとして追加しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
internal class TreeViewEx : TreeView { internal void AddNodeLastChild(TreeNode parentNode, string newKey, string newText, int imageIndex, int selectedImageIndex, object data) { TreeNode newNode = new TreeNode(newText, imageIndex, selectedImageIndex); newNode.Name = newKey; newNode.Tag = data; if (parentNode != null) parentNode.Nodes.Add(newNode); else this.Nodes.Add(newNode); } } |
ついでに[一番上の子として追加する][そのアイテムの次に追加する][そのアイテムの前に追加する]メソッドもつくってしまいましょう。
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 |
public partial class SyncTreeView : UserControl { public void AddNodeFirstChild(TreeNodeEx parentNode, string newText, int imageIndex, int selectedImageIndex, object data) { DateTime dt = DateTime.Now; string newKey = dt.Ticks.ToString(); foreach (TreeViewEx view in SyncGroup.TreeViews) { if (parentNode == null) { view.AddNodeFirstChild(null, newKey, newText, imageIndex, selectedImageIndex, data); continue; } TreeNode[] nodes = view.Nodes.Find(parentNode.Key, true); if (nodes.Length > 0) view.AddNodeFirstChild(nodes[0], newKey, newText, imageIndex, selectedImageIndex, data); } } public void AddNodeNext(TreeNodeEx targetNode, string newText, int imageIndex, int selectedImageIndex, object data) { if (targetNode == null) return; DateTime dt = DateTime.Now; string newKey = dt.Ticks.ToString(); foreach (TreeViewEx view in SyncGroup.TreeViews) { TreeNode[] nodes = view.Nodes.Find(targetNode.Key, true); if (nodes.Length > 0) view.AddNodeNext(nodes[0], newKey, newText, imageIndex, selectedImageIndex, data); } } public void AddNodePrev(TreeNodeEx targetNode, string newText, int imageIndex, int selectedImageIndex, object data) { if (targetNode == null) return; DateTime dt = DateTime.Now; string newKey = dt.Ticks.ToString(); foreach (TreeViewEx view in SyncGroup.TreeViews) { TreeNode[] nodes = view.Nodes.Find(targetNode.Key, true); if (nodes.Length > 0) view.AddNodePrev(nodes[0], newKey, newText, imageIndex, selectedImageIndex, data); } } } |
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 |
internal class TreeViewEx : TreeView { internal void AddNodeFirstChild(TreeNode parentNode, string newKey, string newText, int imageIndex, int selectedImageIndex, object data) { TreeNode newNode = new TreeNode(newText, imageIndex, selectedImageIndex); newNode.Name = newKey; newNode.Tag = data; if (parentNode != null) parentNode.Nodes.Insert(0, newNode); else this.Nodes.Insert(0, newNode); } internal void AddNodeNext(TreeNode targetNode, string newKey, string newText, int imageIndex, int selectedImageIndex, object data) { if (targetNode == null) return; TreeNode newNode = new TreeNode(newText, imageIndex, selectedImageIndex); newNode.Name = newKey; newNode.Tag = data; TreeNode parentNode = targetNode.Parent; if (parentNode != null) parentNode.Nodes.Insert(targetNode.Index + 1, newNode); else this.Nodes.Insert(targetNode.Index + 1, newNode); } internal void AddNodePrev(TreeNode targetNode, string newKey, string newText, int imageIndex, int selectedImageIndex, object data) { if (targetNode == null) return; TreeNode newNode = new TreeNode(newText, imageIndex, selectedImageIndex); newNode.Name = newKey; newNode.Tag = data; TreeNode parentNode = targetNode.Parent; if (parentNode != null) parentNode.Nodes.Insert(targetNode.Index, newNode); else this.Nodes.Insert(targetNode.Index, newNode); } } |
ノードを削除する
追加とセットになるのが削除です。ノードを削除するメソッドは以下のとおりです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public partial class SyncTreeView : UserControl { public void DeleteNode(TreeNodeEx targetNode) { if (targetNode == null) return; foreach (TreeView tree in SyncGroup.TreeViews) { TreeNode[] nodes = tree.Nodes.Find(targetNode.Key, true); if (nodes.Length == 1) { nodes[0].Remove(); } } } } |