I'm trying to add nodes dynamically during run-time to an existing tree-view emulating windows explorer. I have code that works, but because of the amount of recursion that takes place it takes 2-3 minutes to check for all of the files on the c: drive and create the tree.
What I would like to do instead is something like this:
-NodeClickEvent-
if has children { do nothing }
else { add children and grandchildren to selected node }
This is so that it does not have to load the entire tree, but instead loads a couple layers at a time on a per-click basis.
http://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode
Look at demo 2 in the same article
when creating a treeview item, attach a dummy object
On expansion of each treeview item, delete the dummy child if it is in and add actual children if at all it has.
Its very clearly explained in the above quoted article
IF you are not very familiar wtih tree view , then you can first take this tutorial http://www.dotnetperls.com/treeview
and this tutorial describes how to use treelist.
And these following links explain that what you are looking for
http://msdn.microsoft.com/en-us/library/aa984278%28VS.71%29.aspx
http://msdn.microsoft.com/en-us/library/aa645739%28v=vs.71%29.aspx
Thanks for all the input; I think I finally figured out how to do what I was looking for here: An unhandled exception of type 'System.NullReferenceException' occurring when clicking TreeNode
My Code is:
public Form1()
{
InitializeComponent();
this.treeView1.NodeMouseClick += new TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseClick);
PopulateTreeView();
}
private void PopulateTreeView()
{
TreeNode rootNode;
DirectoryInfo info = new DirectoryInfo(#"c:\\");
if (info.Exists)
{
rootNode = new TreeNode(info.Name);
rootNode.Tag = info;
GetDirectories(info.GetDirectories(), rootNode);
treeView1.Nodes.Add(rootNode);
}
}
private void GetDirectories(DirectoryInfo[] subDirs, TreeNode nodeToAddTo)
{
TreeNode aNode;
//DirectoryInfo[] subSubDirs;
foreach (DirectoryInfo subDir in subDirs)
{
aNode = new TreeNode(subDir.Name, 0, 0);
aNode.Tag = subDir;
aNode.ImageKey = "folder";
/* try
{
subSubDirs = subDir.GetDirectories();
if (subSubDirs.Length != 0)
{
GetDirectories2(subSubDirs, aNode);
}
}
catch (System.UnauthorizedAccessException)
{
subSubDirs = new DirectoryInfo[0];
}*/
nodeToAddTo.Nodes.Add(aNode);
}
}
void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
try
{
DirectoryInfo d = new DirectoryInfo(#e.Node.FullPath);
if (e.Node.Nodes.Count > 0) { /*Do Nothing.*/ } else { GetDirectories(d.GetDirectories(), e.Node); e.Node.Expand(); }
TreeNode newSelected = e.Node;
listView1.Items.Clear();
DirectoryInfo nodeDirInfo = (DirectoryInfo)newSelected.Tag;
ListViewItem.ListViewSubItem[] subItems;
ListViewItem item = null;
foreach (DirectoryInfo dir in nodeDirInfo.GetDirectories())
{
item = new ListViewItem(dir.Name, 0);
subItems = new ListViewItem.ListViewSubItem[]
{new ListViewItem.ListViewSubItem(item, "Directory"),
new ListViewItem.ListViewSubItem(item,
dir.LastAccessTime.ToShortDateString())};
item.SubItems.AddRange(subItems);
listView1.Items.Add(item);
}
foreach (FileInfo file in nodeDirInfo.GetFiles())
{
item = new ListViewItem(file.Name, 1);
subItems = new ListViewItem.ListViewSubItem[]
{ new ListViewItem.ListViewSubItem(item, "File"),
new ListViewItem.ListViewSubItem(item,
file.LastAccessTime.ToShortDateString())};
item.SubItems.AddRange(subItems);
listView1.Items.Add(item);
}
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
catch (Exception ex)
{
if (ex is System.NullReferenceException || ex is System.UnauthorizedAccessException)
{
// Do Nothing.
}
}
}`
Related
I would like an algorithm which generates a file structure starting from a user specified directory, but have it only show a specific type of file (.resx). So far I have the code below, which shows the file structure and displays only .resx files, but the problem is that it shows all of the directories which do not contain a .resx file as well. i.e. if a treeviewitem or any of its children does not contain a .resx file, it should not be there.
void DirSearch(string sDir, TreeViewItem parentItem)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
TreeViewItem item = new TreeViewItem();
item.Header = d;
parentItem.Items.Add(item);
foreach (string f in Directory.GetFiles(d, "*.resx"))
{
TreeViewItem subitem = new TreeViewItem();
subitem.Header = f;
subitem.Tag = f;
item.Items.Add(subitem);
}
DirSearch(d, item);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
Add the TreeViewItem representing a directory to its parent only if it has children (*.resx files, or sub-directories containing *.resx files). Note that DirSearch is called recursively before that check is being made.
void DirSearch(string sDir, TreeViewItem parentItem)
{
......
foreach (string d in Directory.GetDirectories(sDir))
{
TreeViewItem item = new TreeViewItem();
item.Header = d;
foreach (string f in Directory.GetFiles(d, "*.resx"))
{
TreeViewItem subitem = new TreeViewItem();
subitem.Header = f;
subitem.Tag = f;
item.Items.Add(subitem);
}
DirSearch(d, item);
if (item.Items.Count > 0)
parentItem.Items.Add(item);
}
......
}
on one of my drives I have a folder structure ex
d:\
123
Code
testfile.cs
Database
Backup.mdb
Requirements
Sprint1.xls
234
20132305
20132205
20132105
Database
I would like to in my treeview show the following
d:\
123
Code
testfile.cs
Database
Backup.mdb
234
Database
i.e only show folders and subfolders for "code" and "database"
Here is the code to load the treeview
folderLst = {"123","234"}
private void PopulateTreeView()
{
TreeNode rootNode;
foreach (string f in folderLst)
{
DirectoryInfo info = new DirectoryInfo(#"d:\");
if (info.Exists)
{
rootNode = new TreeNode(info.Name);
rootNode.Tag = info;
GetDirectories(info.GetDirectories(), rootNode);
treeView1.Nodes.Add(rootNode);
}
}
}
private void GetDirectories(DirectoryInfo[] subDirs, TreeNode nodeToAddTo)
{
TreeNode aNode;
DirectoryInfo[] subSubDirs;
foreach (DirectoryInfo subDir in subDirs)
{
aNode = new TreeNode(subDir.Name, 0, 0);
aNode.Tag = subDir;
subSubDirs = subDir.GetDirectories();
if (subSubDirs.Length != 0)
{
GetDirectories(subSubDirs, aNode);
}
nodeToAddTo.Nodes.Add(aNode);
}
}
any help is appreciated
You have the following code
foreach (DirectoryInfo subDir in subDirs)
{
aNode = new TreeNode(subDir.Name, 0, 0);
aNode.Tag = subDir;
subSubDirs = subDir.GetDirectories();
if (subSubDirs.Length != 0)
{
GetDirectories(subSubDirs, aNode);
}
nodeToAddTo.Nodes.Add(aNode);
}
You can modify it to not add the desired folders
foreach (DirectoryInfo subDir in subDirs)
{
if(subDir.Name.Contains("Code") || subDir.Name.Contains("Database"))
{
aNode = new TreeNode(subDir.Name, 0, 0);
aNode.Tag = subDir;
subSubDirs = subDir.GetDirectories();
if (subSubDirs.Length != 0)
{
GetDirectories(subSubDirs, aNode);
}
nodeToAddTo.Nodes.Add(aNode);
}
}
I'm trying to read a file line by line, which works perfectly but I want to seperate the results I get into subitems in the listview.
I am also searching for all .jar files in the folder so I can use those as the name (first column). The second column needs to have the "version", the third column the "author" and the fourth column the "description".
Here's one of the text files I receive from within the jar files:
name: AFK
main: com.github.alesvojta.AFK.AFK
version: 2.0.5
author: Ales Vojta / schneckk
description: Provides AFK messages
website: http://dev.bukkit.org/server-mods/afk/
commands:
afk:
description: Provides AFK message when player types /afk.
usage: /<command>
this is the code I have right now:
private List<string> GetInstalledPlugins()
{
List<string> list = new List<string>();
lvInstalledPlugins.Items.Clear();
if (!Directory.Exists(Environment.CurrentDirectory + "\\plugins"))
{
Directory.CreateDirectory(Environment.CurrentDirectory + "\\plugins");
DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\plugins");
FileInfo[] fileInfo = di.GetFiles("*.jar");
foreach (var info in fileInfo)
{
//lvInstalledPlugins.Items.Add(info.Name);
list.Add(info.Name);
}
}
else
{
DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\plugins");
FileInfo[] fileInfo = di.GetFiles("*.jar");
foreach (var info in fileInfo)
{
//lvInstalledPlugins.Items.Add(info.Name);
list.Add(info.Name);
}
}
return list;
}
private void test(IEnumerable<string> list)
{
List<ListViewItem> PluginList = new List<ListViewItem>();
var items = new string[4];
try
{
foreach (var ListItem in list)
{
Console.WriteLine(ListItem);
var name = Environment.CurrentDirectory + "\\plugins\\" + ListItem;
var zip = new ZipInputStream(File.OpenRead(name));
var filestream = new FileStream(name, FileMode.Open, FileAccess.Read);
var zipfile = new ZipFile(filestream);
ZipEntry item;
while ((item = zip.GetNextEntry()) != null)
{
if (item.Name == "plugin.yml")
{
using (var s = new StreamReader(zipfile.GetInputStream(item)))
{
string line;
while ((line = s.ReadLine()) != null)
{
if (line.Contains("name"))
{
items[0] = line;
}
if (line.Contains("version"))
{
items[1] = line;
}
if (line.Contains("author"))
{
items[2] = line;
}
if (line.Contains("description"))
{
items[3] = line;
}
try
{
var lvitem = new ListViewItem(items);
lvitem.Name = items[0];
lvitem.Text = items[0];
lvitem.SubItems.Add(items[1]);
lvitem.SubItems.Add(items[2]);
lvitem.SubItems.Add(items[3]);
PluginList.Add(lvitem);
}
catch (Exception)
{
}
}
lvInstalledPlugins.Items.AddRange(PluginList.ToArray());
}
}
}
}
This doesn't seem to work :/, any ideas? I've been working on this for the whole day and can't seem to get it to work :(.
Not exactly sure of your question, but going by the title, the answer to the question below may provide some assistance.
C# listView, how do I add items to columns 2, 3 and 4 etc?
I have a trouble with Expand / Collapse icon in TreeView
What I get : http://i.imgur.com/dl5Lg.jpg
What I did :
C# code :
public static void TreeLoad(TreeView tree, string #source)
{
XmlDocument document = new XmlDocument();
//TreeView tree = new TreeView();
try
{
if (File.Exists(source))
{
document.Load(source);
tree.Nodes.Clear();
XmlNodeList category = document.SelectNodes("/parent/Categories");
//XmlNodeList links = document.SelectNodes("/parent/Categories/link");
foreach (XmlNode node in category)
{
TreeNode t1 = new TreeNode(node.Attributes["Name"].Value);
tree.Nodes.Add(t1);
//t1.ShowCheckBox = true;
if (node.HasChildNodes)
{
//foreach (XmlNode nod in links)
foreach (XmlNode nod in node.ChildNodes)
{
TreeNode t2 = new TreeNode(nod.Attributes["name"].Value);
tree.Nodes.Add(t2);
}
}
}
//tree.Nodes[0].CollapseAll();
//document.Save(source);
}
else
{
messages = NOTFOUND;
}
}
catch (Exception ect)
{
//exist.InnerText = ect.Message;
messages = ect.Message;
}
finally
{
// document.Save(source);
}
//return tree;
}
URLStorageCtrl.TreeLoad(tree, "example.xml");
ASP.NET code
<asp:TreeView ID="tree" runat="server"></asp:TreeView>
I'm using 4-tier architecture so please do not redirect me to design page, I use only coding.
yeah, of course. you added all nodes to tree as its root.
this code:
tree.Nodes.Add(t2);
change to :
t1.ChildNodes.Add(t2);
I have a String List with items like this
"Root"
"Root/Item1"
"Root/Item2"
"Root/Item3/SubItem1"
"Root/Item3/SubItem2"
"Root/Item4/SubItem1"
"AnotherRoot"
How do I transfer this stringlist into a treeview ?
You can split each item into it's substrings. Then via recursion look for each item, if the parent exists add to it, and if the parent doesn't exists create it.
If you can't see how to do it, i`ll post you a sample code
Sample Code
public void AddItem(TreeView treeControl, TreeNode parent, string item)
{
TreeNodeCollection nodesRef = (parent != null) ? parent.Nodes : treeControl.Nodes;
string currentNodeName;
if (-1 == item.IndexOf('/')) currentNodeName = item;
else currentNodeName = item.Substring(0, item.IndexOf('/'));
if (nodesRef.ContainsKey(currentNodeName))
{
AddItem(treeControl, nodesRef[currentNodeName], item.Substring(currentNodeName.Length+1));
}
else
{
TreeNode newItem = nodesRef.Add(currentNodeName, currentNodeName);
if (item.Length > currentNodeName.Length)
{
AddItem(treeControl, newItem, item.Substring(item.IndexOf('/', currentNodeName.Length) + 1));
}
}
}
And the caller example:
string[] stringArr = {
"Root",
"Root/Item1",
"Root/Item2",
"Root/Item3/SubItem1",
"Root/Item3/SubItem2",
"Root/Item4/SubItem1",
"AnotherRoot"
};
foreach (string item in stringArr)
{
AddItem(treeView1, null, item);
}
One way is to iterate the items split the item and push them on a list and if the parent doesn't match pop an item from the list until the stack is empty or you have a match.
You can use this code:
private void button1_Click(object sender, EventArgs e) {
List<String> paths = new List<String> {
"Root", "Root/Item1", "Root/Item2", "Root/Item3/SubItem1",
"Root/Item3/SubItem2", "Root/Item4/SubItem1", "AnotherRoot"
};
List<TreeNode> nodeCollection = new List<TreeNode>();
foreach (var path in paths) {
AddPath(nodeCollection, path);
}
treeView1.Nodes.Clear();
treeView1.Nodes.AddRange(nodeCollection.ToArray());
}
public void AddPath(List<TreeNode> collection, String path) {
LinkedList<String> pathToBeAdded = new LinkedList<String>(path.Split(new String[] { #"/" }, StringSplitOptions.RemoveEmptyEntries));
if (pathToBeAdded.Count == 0) {
return;
}
String rootPath = pathToBeAdded.First.Value;
TreeNode root = collection.FirstOrDefault(n => n.Text.Equals(rootPath));
if (root == null) {
root = new TreeNode(rootPath);
collection.Add(root);
}
pathToBeAdded.RemoveFirst();
AddPath(root, pathToBeAdded);
}
public void AddPath(TreeNode rootNode, LinkedList<String> pathToBeAdded) {
if (pathToBeAdded.Count == 0) {
return;
}
String part = pathToBeAdded.First.Value;
TreeNode subNode = null;
if (!rootNode.Nodes.ContainsKey(part)) {
subNode = rootNode.Nodes.Add(part, part);
} else {
subNode = rootNode.Nodes[part];
}
pathToBeAdded.RemoveFirst();
AddPath(subNode, pathToBeAdded);
}
Hope this helps.
Ricardo Lacerda Castelo Branco