private void Bgw_DoWork(object sender, DoWorkEventArgs e)
{
fileslist = GetFiles(textBoxFileDirectory.Text, "*.*", fsw.IncludeSubdirectories).ToList();
if (bgw.CancellationPending == true)
{
e.Cancel = true;
return;
}
if (fileslist.Count > 0)
{
bgw.ReportProgress(fileslist.Count);
for (int i = 0; i < fileslist.Count; i++)
{
if (bgw.CancellationPending == true)
{
e.Cancel = true;
return;
}
FileInfo info = new FileInfo(fileslist[i]);
if (File.Exists(info.FullName))
{
dic.Add(fileslist[i], info.Length);
}
}
}
}
until now i used to make :
fileslist = GetFiles(#"D:\", "*.*", fsw.IncludeSubdirectories).ToList();
but now i wan to use the text inside the textBoxFileDirectory control the problem is that you can't use ui inside the dowork event.
I tried this :
textBoxFileDirectory.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() => { fileslist = GetFiles(textBoxFileDirectory.Text, "*.*", fsw.IncludeSubdirectories).ToList(); }));
but this make the whole application to freeze and then to continue working when getting files from drive D but it's freezing when getting the files.
but when trying to get the files this way from C drive it's also freezing but after some time i'm getting this message :
This is the GetFiles method :
public static IEnumerable<string> GetFiles(string root, string searchPattern, bool includeSubDirectories)
{
Stack<string> pending = new Stack<string>();
pending.Push(root);
while (pending.Count != 0)
{
var path = pending.Pop();
string[] next = null;
try
{
next = Directory.GetFiles(path, searchPattern);
}
catch { }
if (next != null && next.Length != 0)
foreach (var file in next) yield return file;
try
{
if (includeSubDirectories)
{
next = Directory.GetDirectories(path);
foreach (var subdir in next) pending.Push(subdir);
}
}
catch { }
}
}
Related
I have a backgroundworker dowork where inside I start a new backgroundworker
DirectoryInfo MySubDirectory;
List<FileInfo> l;
object[] CurrentStatus;
private void _FileProcessingWorker_DoWork(object sender, DoWorkEventArgs e)
{
int countmore = 0;
try
{
DirectoryInfo[] MySubDirectories = (DirectoryInfo[])e.Argument;
for (int i = 0; i < MySubDirectories.GetLength(0); i++)
{
MySubDirectory = MySubDirectories[i];
l = new List<FileInfo>();
if (_FileCountingWorker.IsBusy == false)
_FileCountingWorker.RunWorkerAsync();
CurrentStatus = new object[6];
int totalFiles = l.Count;
CurrentStatus[3] = i.ToString();
countmore += totalFiles;
CurrentStatus[4] = countmore;
_FileProcessingWorker.ReportProgress(0, CurrentStatus);
string CurrentDirectory = "Current Directory: " + MySubDirectory.Name;
foreach (FileInfo MyFile in l)
{
CurrentStatus = new object[6];
if (_FileProcessingWorker.CancellationPending)
{
e.Cancel = true;
return;
}
if (MyFile.Extension.ToLower() == ".cs" || MyFile.Extension.ToLower() == ".vb")
{
string CurrentFile = "Current File: " + MyFile.Name;
string CurrentFileWithPath = MyFile.FullName;
CurrentStatus[0] = CurrentDirectory;
CurrentStatus[1] = CurrentFile;
_FileProcessingWorker.ReportProgress(0, CurrentStatus);
List<string> Result = SearchInFile(CurrentFileWithPath, "if");
if (Result != null && Result.Count > 0)
{
CurrentStatus[2] = Result;
_FileProcessingWorker.ReportProgress(0, CurrentStatus);
}
}
}
}
}
catch (Exception err)
{
return;
}
}
I'm checking the other backgroundworker is not busy if not start it
if (_FileCountingWorker.IsBusy == false)
_FileCountingWorker.RunWorkerAsync();
In the new backgroundworker dowork event
private void _FileCountingWorker_DoWork(object sender, DoWorkEventArgs e)
{
CountFiles(MySubDirectory, l);
}
In CountFiles
int countingFiles = 0;
private void CountFiles(DirectoryInfo di, List<FileInfo> l)
{
try
{
l.AddRange(di.EnumerateFiles());
}
catch
{
string fff = "";
}
try
{
if (di.FullName != BasePath)
{
IEnumerable<DirectoryInfo> subDirs = di.EnumerateDirectories();
if (subDirs.Count() > 0)
{
foreach (DirectoryInfo dir in subDirs)
{
CountFiles(dir, l);
countingFiles += 1;
if (countingFiles == 8382)
{
string hhhhh = "";
}
CurrentStatus[5] = countingFiles;
_FileCountingWorker.ReportProgress(0,CurrentStatus);
}
}
}
}
catch
{
string yyy = "";
}
}
Then in the second backgroundworker progresschanged
private void _FileCountingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (typeof(object[]) == e.UserState.GetType())
{
object[] StatusMsg = (object[])e.UserState;
if (6 == StatusMsg.GetLength(0))
{
if (StatusMsg[5] != null)
{
lblCountingFiles.Text = StatusMsg[5].ToString();
}
}
}
}
The exception is on the line:
lblCountingFiles.Text = StatusMsg[5].ToString();
Cross-thread operation not valid: Control 'lblCountingFiles' accessed from a thread other than the thread it was created on
I'm updating the label in the ProgressChanged event. Why am I getting the exception?
And how should I solve it?
You are calling _FileCountingWorker.RunWorkerAsync(); in DoWork from another BackgroundWorker thread.
So when _FileCountingWorker reports progress it wont come back to the UI thread because it is not started from UI thread. That's why you are getting cross thread exception.
Try to call _FileCountingWorker.RunWorkerAsync() from UI thread or from _FileProcessingWorker_ProgressChanged event.
Otherwise you can use:
private void _FileCountingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread
{
Dispatcher.Invoke(new Action<object, ProgressChangedEventArgs>(_FileCountingWorker_ProgressChanged), sender, e);
return;
}
if (typeof(object[]) == e.UserState.GetType())
{
object[] StatusMsg = (object[])e.UserState;
if (6 == StatusMsg.GetLength(0))
{
if (StatusMsg[5] != null)
{
lblCountingFiles.Text = StatusMsg[5].ToString();
}
}
}
}
I think the problem is on the main thread you have
object[] CurrentStatus;
in the background you could be newing it before reports progress gets to it
(or at the same time)
kill the above
just create the object in the do_work
object[] CurrentStatus = new object[6];
I have a simple application that executes a function in a separate thread via a BackgroundWorker and am running into issues. I am collecting a string array of values and passing that back to my ProgressChanged event via the ReportProgress method and I'm running into a problem where the thread continues and is so fast, it outruns the ProgressChanged event and overwrites the values before they can be added to a grid. Below is my code...
Button Click Event Fires my thread...
private void LoadButton_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(WorkingPathTextBox.Text))
{
this.dataGridView1.Rows.Clear();
this.progressBar1.Visible = true;
this.LoadButton.Visible = false;
this.BrowseButton.Enabled = false;
this.WorkingPathTextBox.Enabled = false;
this.CancelBtn.Visible = true;
this.ProcessingLabel.Visible = true;
beginTime = DateTime.Now;
WorkflowCleanup wc = new WorkflowCleanup();
wc.WorkflowPath = this.WorkingPathTextBox.Text;
backgroundWorker1.RunWorkerAsync(wc);
}
}
In the DoWork, it loads the class where my work exists...
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.ComponentModel.BackgroundWorker worker;
worker = (System.ComponentModel.BackgroundWorker)sender;
// Get the Words object and call the main method.
WorkflowCleanup wc = (WorkflowCleanup)e.Argument;
wc.LoadAssemblies(worker, e);
wc.LoadDataDefinitions(worker, e);
wc.LoadDataDefinitionsDirty(worker, e);
wc.LoadProcesses(worker, e);
wc.LoadProcessesDirty(worker, e);
wc.LoadWorkflows(worker, e);
// wc.UpdateWorkflows(worker, e);
}
WorkflowCleanup class...the ReportProgress in stuck right in the middle of the try/catch because I could not figure out what was causing the problem. So, I moved it in the try, and even had to add a Thread.Sleep(100) to slow the process down to give the ProgressChanged event time enough to add the row of data I passed it to the grid before it was overridden...
namespace WorkflowMaintenance
{
public class WorkflowCleanup
{
private int errorCount = 0;
private int fixCount = 0;
public class Workflow
{
// code truncated
}
public class WorkflowAssembly
{
// code truncated
}
public class DataDefinition
{
// code truncated
}
public class CurrentState
{
public int Percentage;
public string StateString;
public List<string[]> ProcessResults;
public string[] Result;
public int ErrorCount;
public int FixCount;
}
public void LoadAssemblies(System.ComponentModel.BackgroundWorker worker, System.ComponentModel.DoWorkEventArgs e)
{
CurrentState state = new CurrentState();
fixCount = 0;
errorCount = 0;
string[] asmbfiles = System.IO.Directory.GetFiles(WorkflowPath + "\\Assemblies", "*.asmb", System.IO.SearchOption.AllDirectories);
int asmbIndex = 0;
Assemblies = new List<WorkflowAssembly>();
// Assemblies (NEW)
foreach (string asmb in asmbfiles)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
else
{
//results = new List<string[]>();
asmbIndex += 1;
int percentage = (asmbIndex * 100) / asmbfiles.Length;
state.StateString = string.Format("Loading Assemblies... {0}%", percentage);
state.Percentage = percentage;
try
{
XDocument xdoc = XDocument.Load(asmb);
XElement asmbElement = xdoc.Descendants(wf + "assembly").First();
XElement asmbTypes = asmbElement.Element(wf + "types");
string asmbid = asmbElement.Attribute("id").Value;
string asmbname = asmbElement.Element(wf + "name").Value;
string asmbpath = asmbElement.Element(wf + "assemblyPath").Value;
Assemblies.Add(new WorkflowAssembly() { ID = asmbid, Name = asmbname, FileName = asmb, AssemblyPath = asmbpath, Types = asmbTypes });
//results.Add(new string[] { "SUCCESS", "ASSEMBLY PROCESSED SUCCESSFULLY", asmbname, asmbid, null, asmb });
state.Result = new string[] { "SUCCESS", "ASSEMBLY PROCESSED SUCCESSFULLY", asmbname, asmbid, null, asmb };
fixCount += 1;
//if (results != null && results.Count > 0)
//{
// state.ProcessResult = results;
//}
state.FixCount = fixCount;
state.ErrorCount = errorCount;
worker.ReportProgress(percentage, state);
Thread.Sleep(100);
}
catch (Exception)
{
// need to report the exception...
errorCount += 1;
}
finally
{
//if (results != null && results.Count > 0)
//{
// state.ProcessResult = results;
//}
//state.FixCount = fixCount;
//state.ErrorCount = errorCount;
//worker.ReportProgress(percentage, state);
}
}
}
}
}
}
ProgressChanged Event...
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// This method runs on the main thread.
WorkflowCleanup.CurrentState state = (WorkflowCleanup.CurrentState)e.UserState;
this.progressBar1.Value = state.Percentage;
this.ProcessingLabel.Text = state.StateString;
this.errorLabel.Text = string.Format("Errors: {0}", state.ErrorCount);
this.fixLabel.Text = string.Format("Fixed: {0}", state.FixCount);
this.ElapsedTimeLabel.Text = string.Format("Elapsed Time: {0}", GetProgressElapsedString());
if (state.Result != null)
{
this.dataGridView1.Rows.Add(state.Result);
}
}
Problem...the problem is that if I have 3 files in the folder (named Assembly1, Assembly2, and Assembly3), the output in the grid shows that all three are named Assembly3. The only way I could fix this was to tell the Thread to sleep. This is not an option as I have to run this for a folder that has approximately 18,000 files and having to sleep for a millisecond would take forever. BUT, I need to get valid results. Help please :-)
Rather than creating the state object outside the loop and mutating it in each iteration, create a new instance for each iteration. This can be done by simply moving the declaration of the variable inside the loop.
i build application and add files to my ListView, I want the last file added each time will emphasize so inside my Foreach statement i added lvFiles.Items[lvFiles.Items.Count - 1].Selected = true; but in this case all the files inside my ListView emphasized and not only the last one
List<string> filesList
foreach (string fileName in filesList)
{
FileInfo fileInfo = new FileInfo(fileName);
if (checkFileCreationDate(fileInfo))
{
if (editcap.isWiresharkFormat(fileInfo.FullName))
{
if (editcap.isLibpcapFormat(fileInfo.FullName))
{
addFileToListBox(fileInfo.FullName, capinfos.getFileDuration(fileInfo.FullName));
}
else if (!editcap.isLibpcapFormat(fileInfo.FullName))
{
fileToAdd = editcap.getNewFileName(fileInfo.FullName);
if (new FileInfo(fileToAdd).Exists && !fileInfo.Exists)
{
addFileToListBox(fileToAdd, capinfos.getFileDuration(fileInfo.FullName));
}
}
}
}
}
private void addFileToListBox(string filePath, string duration)
{
item = new ListViewItem(new string[] { new FileInfo(filePath).Name, duration, "Waiting" });
item.Tag = new FileInfo(filePath).FullName;
}
just put that statement after your foreach and it should work.
like:
foreach(var x in colY)
{
//check file
lvFiles.Items[lvFiles.Items.Count - 1].Selected = false;
//add item here
lvFiles.Items[lvFiles.Items.Count - 1].Selected = true;
}
You need to start by unselecting the previous elements and only then selecting the final one:
foreach (var item in lvFiles.Items)
{
item.Selected = false;
}
lvFiles.Items[lvFiles.Items.Count - 1].Selected = true;
I need help on how to map my drives into a tree view. I can get my drives to show but I can not get all the sub directories. I would like to get my entire drive mapped out into a tree view. Any help would be appreciated. This is what I got so far.
string[] drives = Environment.GetLogicalDrives();
foreach (string dr in drives)
{
TreeNode node = new TreeNode(dr);
node.Tag = dr;
treeView1.Nodes.Add(node);
}
treeView1.CollapseAll();
To do it recursively:
private void fillTree() { // you allready had most of this
string[] drives = Environment.GetLogicalDrives();
foreach(string dr in drives) {
TreeNode node = RecursiveDirWalk(dr);
node.ImageIndex = 0; // drive icon
node.Tag = dr;
treeView1.Nodes.Add(node);
}
}
// now add this
private TreeNode RecursiveDirWalk(string path) {
TreeNode node = new TreeNode(path.Substring(path.LastIndexOf('\\')));
node.ImageIndex = 1; // dir icon
node.Tag = path;
string[] dirs = System.IO.Directory.GetDirectories(path);
for(int t = 0; t < dirs.Length; t++) {
node.Nodes.Add(RecursiveDirWalk(dirs[t]));
}
// Optional if you want files as well:
string[] files = System.IO.Directory.GetFiles(path);
for(int t = 0; t < files.Length; t++) {
TreeNode tn = new TreeNode(System.IO.Path.GetFileName(files[t]));
tn.Tag = files[t];
tn.ImageIndex = 2; // file icon
node.Nodes.Add(tn);
} // end of optional file part
return node;
}
Here's a lazy loading version:
private void fillTree() {
string[] drives = Environment.GetLogicalDrives();
foreach(string dr in drives) {
TreeNode node = new TreeNode(dr);
node.Tag = dr;
node.ImageIndex = 0; // drive icon
node.Tag = dr;
treeView1.Nodes.Add(node);
node.Nodes.Add(new TreeNode("?"));
}
treeView1.BeforeExpand += new TreeViewCancelEventHandler(treeView1_BeforeExpand);
}
void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) {
if((e.Node.Nodes.Count == 1) && (e.Node.Nodes[0].Text=="?")) {
RecursiveDirWalk(e.Node);
}
}
private TreeNode RecursiveDirWalk(TreeNode node) {
string path = (string)node.Tag;
node.Nodes.Clear();
string[] dirs = System.IO.Directory.GetDirectories(path);
for(int t = 0; t < dirs.Length; t++) {
TreeNode n = new TreeNode(dirs[t].Substring(dirs[t].LastIndexOf('\\')+1));
n.ImageIndex = 1; // dir icon
n.Tag = dirs[t];
node.Nodes.Add(n);
n.Nodes.Add(new TreeNode("?"));
}
// Optional if you want files as well:
string[] files = System.IO.Directory.GetFiles(path);
for(int t = 0; t < files.Length; t++) {
TreeNode tn = new TreeNode(System.IO.Path.GetFileName(files[t]));
tn.Tag = files[t];
tn.ImageIndex = 2; // file icon
node.Nodes.Add(tn);
} // end of optional file part
return node;
}
Here's the code used to display a tree with only the drives shown at first, adding to the tree as the user clicks on the nodes. This code will not display empty drives. Adding icons to each node is left as an exercise for the student:
private static string PLACEHOLDER = "...";
private void ListDrives()
{
string[] drives = Environment.GetLogicalDrives();
foreach (string drive in drives)
{
if (Directory.Exists(drive))
{
TreeNode node = new TreeNode(drive);
node.Tag = drive;
this.treeViewFolders.Nodes.Add(node);
node.Nodes.Add(new TreeNode(PLACEHOLDER));
}
}
this.treeViewFolders.BeforeExpand += new TreeViewCancelEventHandler(treeView_BeforeExpand);
}
void treeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
if (e.Node.Nodes.Count > 0)
{
if (e.Node.Nodes[0].Text == PLACEHOLDER)
{
e.Node.Nodes.Clear();
string[] dirs = Directory.GetDirectories(e.Node.Tag.ToString());
foreach (string dir in dirs)
{
DirectoryInfo di = new DirectoryInfo(dir);
TreeNode node = new TreeNode(di.Name);
node.Tag = dir;
try
{
if (di.GetDirectories().GetLength(0) > 0)
node.Nodes.Add(null, PLACEHOLDER);
}
catch (UnauthorizedAccessException)
{
// TODO: update node images
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "ExplorerForm", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
e.Node.Nodes.Add(node);
}
}
}
}
}
I'm trying to populate a treeview from a list of folder path, for example:
C:\WINDOWS\addins
C:\WINDOWS\AppPatch
C:\WINDOWS\AppPatch\MUI
C:\WINDOWS\AppPatch\MUI\040C
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI\0409
with an ouput like this:
├───addins
├───AppPatch
│ └───MUI
│ └───040C
├───Microsoft.NET
│ └───Framework
│ └───v2.0.50727
│ └───MUI
│ └───0409
Notice there's no 'C:\WINDOWS\Microsoft.NET' or 'C:\WINDOWS\Microsoft.NET\Framework' in the list. I've been working on this for almost two days and there's a bunch of bug in my code. Hope I can get help from here.
Thanks.
Eric
private void Form1_Load(object sender, EventArgs e)
{
var paths = new List<string>
{
#"C:\WINDOWS\AppPatch\MUI\040C",
#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727",
#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI",
#"C:\WINDOWS\addins",
#"C:\WINDOWS\AppPatch",
#"C:\WINDOWS\AppPatch\MUI",
#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI\0409"
};
treeView1.PathSeparator = #"\";
PopulateTreeView(treeView1, paths, '\\');
}
private static void PopulateTreeView(TreeView treeView, IEnumerable<string> paths, char pathSeparator)
{
TreeNode lastNode = null;
string subPathAgg;
foreach (string path in paths)
{
subPathAgg = string.Empty;
foreach (string subPath in path.Split(pathSeparator))
{
subPathAgg += subPath + pathSeparator;
TreeNode[] nodes = treeView.Nodes.Find(subPathAgg, true);
if (nodes.Length == 0)
if (lastNode == null)
lastNode = treeView.Nodes.Add(subPathAgg, subPath);
else
lastNode = lastNode.Nodes.Add(subPathAgg, subPath);
else
lastNode = nodes[0];
}
}
}
for a linq'y version:
public static TreeNode MakeTreeFromPaths(List<string> paths, string rootNodeName = "", char separator = '/')
{
var rootNode = new TreeNode(rootNodeName);
foreach (var path in paths.Where(x => !string.IsNullOrEmpty(x.Trim()))) {
var currentNode = rootNode;
var pathItems = path.Split(separator);
foreach (var item in pathItems) {
var tmp = currentNode.Nodes.Cast<TreeNode>().Where(x => x.Text.Equals(item));
currentNode = tmp.Count() > 0 ? tmp.Single() : currentNode.Nodes.Add(item);
}
}
return rootNode;
}
ehosca answer is correcr, but there is a little problem,
when I change paths to like this
C:\WINDOWS\AppPatch\MUI\040C
D:\WIS\Microsoft.NET\Framework\v2.0.50727
E:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI
C:\WINDOWS\addins
C:\WINDOWS\AppPatch
C:\WINDOWS\AppPatch\MUI
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI\0409
It will popoulate treeview like this.
But adding some extra code we can avoid this situation. So I changed the code in PopulateTreeView
private static void PopulateTreeView(TreeView treeView, string[] paths, char pathSeparator)
{
TreeNode lastNode = null;
string subPathAgg;
foreach (string path in paths)
{
subPathAgg = string.Empty;
foreach (string subPath in path.Split(pathSeparator))
{
subPathAgg += subPath + pathSeparator;
TreeNode[] nodes = treeView.Nodes.Find(subPathAgg, true);
if (nodes.Length == 0)
if (lastNode == null)
lastNode = treeView.Nodes.Add(subPathAgg, subPath);
else
lastNode = lastNode.Nodes.Add(subPathAgg, subPath);
else
lastNode = nodes[0];
}
lastNode = null; // This is the place code was changed
}
}
Now it works fine like this
I took your code, and it work very well,
but i made just a little modification for improving the load speed
when it is used whit a large list of files
it seems like find operation, and string operations generally are very slow
private TreeNode PopulateTreeNode2(string[] paths, string pathSeparator)
{
if (paths == null)
return null;
TreeNode thisnode = new TreeNode();
TreeNode currentnode;
char[] cachedpathseparator = pathSeparator.ToCharArray();
foreach (string path in paths) {
currentnode = thisnode;
foreach (string subPath in path.Split(cachedpathseparator))
{
if (null == currentnode.Nodes[subPath])
currentnode = currentnode.Nodes.Add(subPath, subPath);
else
currentnode = currentnode.Nodes[subPath];
}
}
return thisnode;
}
then you can use:
string[] paths = {
#"C:\WINDOWS\AppPatch\MUI\040C",
#"D:\WINDOWS\Microsoft.NET\Framework\v2.0.50727",
#"E:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI",
#"C:\WINDOWS\addins",
#"C:\WINDOWS\AppPatch",
#"C:\WINDOWS\AppPatch\MUI",
#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI\0409"
};
TreeView treeview = new TreeView();
treeview.Nodes.Add(PopulateTreeNode2(paths, "\\"));
NOTE: maybe some string sensitivity check will be needed in both solutions,
in order to prevent some folders re creations.
because some url could be pointing to the same folder on the disk
but spelled different such as:
Windows ; WinDOWs , WINDOWS
Here's some very old code I once used to create an ASP.NET treeview from code (assuming TreeView has an ID of TreeViewFolders):
protected void Page_Load(object sender, EventArgs e)
{
GenerateTreeView(#"C:\WINDOWS\");
}
private void GenerateTreeView(string rootPath)
{
GetFolders(System.IO.Path.GetFullPath(rootPath), TreeViewFolders.Nodes);
TreeViewFolders.ExpandDepth = 1;
}
// recursive method to load all folders and files into tree
private void GetFolders(string path, TreeNodeCollection nodes)
{
// add nodes for all directories (folders)
string[] dirs = Directory.GetDirectories(path);
foreach (string p in dirs)
{
string dp = p.Substring(path.Length);
nodes.Add(Node("", p.Substring(path.Length), "folder"));
}
// add nodes for all files in this directory (folder)
string[] files = Directory.GetFiles(path, "*.*");
foreach (string p in files)
{
nodes.Add(Node(p, p.Substring(path.Length), "file"));
}
// add all subdirectories for each directory (recursive)
for (int i = 0; i < nodes.Count; i++)
{
if (nodes[i].Value == "folder")
GetFolders(dirs[i] + "\\", nodes[i].ChildNodes);
}
}
// create a TreeNode from the specified path, text and type
private TreeNode Node(string path, string text, string type)
{
TreeNode n = new TreeNode();
n.Value = type;
n.Text = text;
return n;
}
private void Form2_Load(object sender, EventArgs e)
{
treeView1.CheckBoxes = true;
foreach (TreeNode node in treeView1.Nodes)
{
node.Checked = true;
}
string[] drives = Environment.GetLogicalDrives();
foreach (string drive in drives)
{
// treeView1.Nodes[0].Nodes[1].Checked = true;
DriveInfo di = new DriveInfo(drive);
int driveImage;
switch (di.DriveType)
{
case DriveType.CDRom:
driveImage = 3;
break;
case DriveType.Network:
driveImage = 6;
break;
case DriveType.NoRootDirectory:
driveImage = 8;
break;
case DriveType.Unknown:
driveImage = 8;
break;
default:
driveImage = 2;
break;
}
TreeNode node = new TreeNode(drive.Substring(0, 1), driveImage, driveImage);
node.Tag = drive;
if (di.IsReady == true)
node.Nodes.Add("...");
treeView1.Nodes.Add(node);
}
foreach (TreeNode node in treeView1.Nodes)
{
node.Checked = true;
}
}
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
{
if (e.Node.Nodes.Count > 0)
{
if (e.Node.Nodes[0].Text == "..." && e.Node.Nodes[0].Tag == null)
{
e.Node.Nodes.Clear();
string[] dirs = Directory.GetDirectories(e.Node.Tag.ToString());
foreach (string dir in dirs)
{
DirectoryInfo di = new DirectoryInfo(dir);
TreeNode node = new TreeNode(di.Name, 0, 1);
node.Checked = true;
try
{
node.Tag = dir;
if (di.GetDirectories().Count() > 0)
node.Nodes.Add(null, "...", 0, 0).Checked = node.Checked;
}
catch (UnauthorizedAccessException)
{
node.ImageIndex = 12;
node.SelectedImageIndex = 12;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "DirectoryLister", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
finally
{
node.Checked = e.Node.Checked;
e.Node.Nodes.Add(node);
}
}
}
}
}
}
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
button1.Enabled = false;
TreeNode node = e.Node;
bool is_checked = node.Checked;
foreach (TreeNode childNode in e.Node.Nodes)
{
childNode.Checked = e.Node.Checked;
}
treeView1.SelectedNode = node;
}
I've managed to create a tree from path list using only for cycles. And it looks like it is the simpliest answer of this question at this moment.
Use this block of code to create a tree. list is the list of your files or folders, treeView1 is your TreeView.
//Creates a tree from given path list
foreach (string path in list)
{
TreeNodeCollection nodes = treeView1.Nodes;
foreach (string path_part in path.Split('\\'))
{
//Here it adds a new node (file or folder)
if (!nodes.ContainsKey(path_part))
nodes.Add(path_part, path_part);
//Go one node deeper
nodes = nodes[path_part].Nodes;
}
}
Note - this may break if you use it with paths that start with the path separator (e.g. /home/user)
And if you want to remove common parts of your paths (or remove single parent nodes), use this block of code right after the previous one:
//This removes "single" TreeNodes (common paths)
while (treeView1.Nodes.Count == 1)
{
//This "unpacks" child TreeNodes from the only parent TreeNode
for (int i = 0; i < treeView1.Nodes[0].Nodes.Count; i++)
treeView1.Nodes.Add(treeView1.Nodes[0].Nodes[i]);
//This removes parent TreeNode
treeView1.Nodes.RemoveAt(0);
}
This will generate an empty tree if all of your paths are the same.