How to programmatically expand a Treeview? - c#

I wrote the following code to iterate my Treeview and find the full path given.
I get the correct position and the listview also shows the correct content, but the treeview is not expanded. It seems that the .Expand() method does not firing.
What could that be about?
The Form with the Treeview is a Dialog, which is initialized once at the program-start and then is refreshed and shown when needed.
Because of the huge number of folders into the deep, I just load 2 levels of folders downward with each manually expanded.
Before I show the Dialog again, I set the SelectedPath to the full path which should be expanded and than calling the ExpandToPath method.
private void treeView1_BeforeExpand(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) {
if(e.Node.Tag != null && e.Node.Nodes.Count > 0)
PopulateTreeView(e.Node, 1);
}
private void PopulateTreeView(TreeNode node, int depth) {
if(node.Tag != null) {
TreeViewTag tag = node.Tag as TreeViewTag;
if(tag.Visited && node.Nodes.Count > 0) {
foreach(TreeNode n in node.Nodes) {
if(depth <= 1)
PopulateTreeView(n, depth + 1);
}
} else {
TreeNode aNode;
try {
DirectoryInfo[] infos = tag.Info.GetDirectories();
foreach(DirectoryInfo subDir in infos) {
try {
aNode = new TreeNode(subDir.Name, 0, 0);
aNode.Tag = new TreeViewTag() { Info = subDir, Visited = true };
aNode.ImageKey = "folderOpen";
if(depth <= 1)
PopulateTreeView(aNode, depth + 1);
node.Nodes.Add(aNode);
} catch(UnauthorizedAccessException ex11) {
} catch(Exception ex12) {
}
}
} catch(UnauthorizedAccessException ex1) {
} catch(Exception ex2) {
}
}
}
}
public void ExpandToPath(string path) {
currentNodeInfo = new DirectoryInfo(path);
TreeNode root = this.treeView1.Nodes[0];
if(path.EndsWith(Path.DirectorySeparatorChar.ToString()))
path = path.Substring(0, path.Length - 1);
Stack<TreeNode> search = new Stack<TreeNode>();
search.Push(root);
while(search.Count > 0) {
TreeNode current = search.Pop();
string compare = (current.Tag as TreeViewTag).Info.FullName;
if(path.Equals(compare)) {
current.Expand();
PopulateListView((current.Tag as TreeViewTag).Info);
break;
} else {
if(path.StartsWith(compare)) {
current.Expand();
foreach(TreeNode node in current.Nodes) {
search.Push(node);
}
}
}
}
search.Clear();
search = null;
}

Related

C# How to use treeView to list the directories and subdirectories without showing the root directory?

From
main folder
|_a
| |_b
| |_c
|_d
|_e
to
a
|_b
|_c
d
e
I want a treeview without the main folder. I found a solution here but it seems that it's incredibly slow. When I first start the program it takes over a minute to load it. Without that code it opens instantly.
So, do you know any why to improve this code or another better code?
EDIT: solved.
Try this, it looks real fast here. You can control whether all nodes are expanded or not.. You need to included the LINQ namspace (using System.Linq;)
// somewhere:
string yourRoot = "D:\\";
treeView1.Nodes.AddRange(getFolderNodes(yourRoot, true).ToArray());
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
TreeNode tn = e.Node.Nodes[0];
if (tn.Text == "...")
{
e.Node.Nodes.AddRange(getFolderNodes(((DirectoryInfo)e.Node.Tag)
.FullName, true).ToArray());
if (tn.Text == "...") tn.Parent.Nodes.Remove(tn);
}
}
List<TreeNode> getFolderNodes(string dir, bool expanded)
{
var dirs = Directory.GetDirectories(dir).ToArray();
var nodes = new List<TreeNode>();
foreach (string d in dirs)
{
DirectoryInfo di = new DirectoryInfo(d);
TreeNode tn = new TreeNode(di.Name);
tn.Tag = di;
int subCount = 0;
try { subCount = Directory.GetDirectories(d).Count(); }
catch { /* ignore accessdenied */ }
if (subCount > 0) tn.Nodes.Add("...");
if (expanded) tn.Expand(); // **
nodes.Add(tn);
}
return nodes;
}
If you are sure you always want to see all levels expaded from the start you can use this function and delete the BeforeExpand code:
List<TreeNode> getAllFolderNodes(string dir)
{
var dirs = Directory.GetDirectories(dir).ToArray();
var nodes = new List<TreeNode>();
foreach (string d in dirs)
{
DirectoryInfo di = new DirectoryInfo(d);
TreeNode tn = new TreeNode(di.Name);
tn.Tag = di;
int subCount = 0;
try { subCount = Directory.GetDirectories(d).Count(); }
catch { /* ignore accessdenied */ }
if (subCount > 0)
{
var subNodes = getAllFolderNodes(di.FullName);
tn.Nodes.AddRange(subNodes.ToArray());
}
nodes.Add(tn);
}
return nodes;
}
You call it as before:
string yourRoot = "D:\\";
Cursor.Current = Cursors.WaitCursor;
treeView1.Nodes.AddRange(getAllFolderNodes(yourRoot).ToArray());
Cursor.Current = Cursors.Default;

Update Treeview with new filepath

I have an Observable collection of Paths.
The thing I want to do is to update my treeView on collection changed.
Could you please help me with creating method that takes Treeview, FilePath and PathSeparator as parameters and adding new node to my treeView. This is what i have now:
private void MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
TreeViewAddNode(TreeView,Path,PathSeparator)
}
TreeViewAddNode(TreeView treeView, string path, char pathSeparator)
{
foreach (string subPath in path.Split(pathSeparator))
{
//Hear should be logic to add new nodes if they don't exist }
}
}
As the Result I wanna have something like that:
C:
--Temp
----File1.txt
----File2.txt
----New Foledr
-------File3.txt
--AnotherFolder
----File4.txt
D:
--New Folder
----File.txt
EDIT
Now with better understanding on what is being asked:
private void TreeViewAddNode(TreeView treeView, string path, char pathSeparator)
{
string[] split = path.Split(pathSeparator);
for(int i = 0; i < split.Length; i++)
{
if(i == 0)
{
checkTreeView(treeView, split[0]);
}
else
{
TreeNode node = treeView1.Nodes.Find(split[i - 1], true)[0];
checkNodes(node, split[i]);
}
}
}
private void checkTreeView(TreeView treeView, string path)
{
bool exists = false;
foreach(TreeNode node in treeView.Nodes)
{
if(node.Text == path)
{
exists = true;
}
}
if(!exists)
{
TreeNode node = treeView.Nodes.Add(path);
node.Name = path;
}
}
private void checkNodes(TreeNode parent, string path)
{
bool exists = false;
foreach(TreeNode node in parent.Nodes)
{
if(node.Text == path)
{
exists = true;
}
}
if(!exists)
{
TreeNode node = parent.Nodes.Add(path);
node.Name = path;
}
}
checkTreeView checks if the path is allready present in the treeview nodes. if it isn't add it to the treeview. Same goes for checkNodes.

C# HTML Tag in a Tag

I have a bit of a pickle. There are a list of images I want to grab on a website. I know how to do that much, but I have to filter out the location of the images.
Such as I'd want to grab the images in a div tag with an id "theseImages", but there are another set of images within another div tag with an id called "notTheseImages". Looping through every tag into ah HtmlElementCollection with the tag "img" would ignore the divs, because it'd also grab the images from "notTheseImages."
Is there a way I could loop through the images while doing a check to see where those images are located in the div tags?
This could help you to do the selection of your current HTML and maybe for future occassions :)
protected HtmlElement[] GetElementsByParent(HtmlDocument document, HtmlElement baseElement = null, params string[] singleSelectors)
{
if (singleSelectors == null || singleSelectors.Length == 0)
{
throw new Exception("Please give at least 1 selector!");
}
IList<HtmlElement> result = new List<HtmlElement>();
bool last = singleSelectors.Length == 1;
string singleSelector = singleSelectors[0];
if (string.IsNullOrWhiteSpace(singleSelector) || string.IsNullOrWhiteSpace(singleSelector.Trim()))
{
return null;
}
singleSelector = singleSelector.Trim();
if (singleSelector.StartsWith("#"))
{
var item = document.GetElementById(singleSelector.Substring(1));
if (item == null)
{
return null;
}
if (last)
{
result.Add(item);
}
else
{
var results = GetElementsByParent(document, item, singleSelectors.Skip(1).ToArray());
if (results != null && results.Length > 0)
{
foreach (var res in results)
{
result.Add(res);
}
}
}
}
else if (singleSelector.StartsWith("."))
{
if (baseElement == null)
{
baseElement = document.Body;
}
foreach (HtmlElement child in baseElement.Children)
{
string cls;
if (!string.IsNullOrWhiteSpace((cls = child.GetAttribute("class"))))
{
if (cls.Split(' ').Contains(singleSelector.Substring(1)))
{
if (last)
{
result.Add(child);
}
else
{
var results = GetElementsByParent(document, child, singleSelectors.Skip(1).ToArray());
if (results != null && results.Length > 0)
{
foreach (var res in results)
{
result.Add(res);
}
}
}
}
}
}
}
else
{
HtmlElementCollection elements = null;
if (baseElement != null)
{
elements = baseElement.GetElementsByTagName(singleSelector);
}
else
{
elements = document.GetElementsByTagName(singleSelector);
}
foreach (HtmlElement item in elements)
{
if (last)
{
result.Add(item);
}
else
{
var results = GetElementsByParent(document, item, singleSelectors.Skip(1).ToArray());
if (results != null && results.Length > 0)
{
foreach (var res in results)
{
result.Add(res);
}
}
}
}
}
return result.ToArray();
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// here we can query
var result = GetElementsByParent(webBrowser1.Document, null, "#theseImages", "img");
}
result would then contain the images that are under #theseImages
Mind you the GetElementsByParent is fairly untested, I just tested it for your use case and it seemed to be ok.
Don't forget to only start the query once you are sure the document is completed ;)

C# Populate treeView with files in a n-depth

I don't know how to show show all data in a treeview control:
here is my code:
private void PopulateTree(string path, int depth, TreeNode parent)
{
if (depth == 0)
{
//This make a child
parent.Nodes.Add(new TreeNode(path);
return;
}
//This makes a parent
TreeNode first = new TreeNode(path);
parent.Nodes.Add(first);
foreach (var v in ListWithPaths)
{
PopulateTree(v, depth - 1, first);
}
}
It only seems to works when depth=1
parent
-parent
--parent
---child
---child
--parent
---child
---child
-/parent
/parent
This is how I see it....
I have found this answer from here :
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];
}
}
}
foreach (var v in ListWithPaths)
{
PopulateTree(v, depth - 1, first);
}
}
Based on the path, it's creating the depth.
If this is not the wished behaviour, you can change the PopulateTreeView-Function accordingly.
There are some unclear moments in your code:
Do you want to explicitly restrict path depth (e.g. show paths up to 3d level only)
What is ListWithPaths? Can two paths have a common node?
To show a single path with restriction (depth) the code could be
private void PopulateTree(String path, TreeNode parent, int depth) {
if (depth == 0) // <- Artificial criterium
return;
if (String.IsNullOrEmpty(path))
return;
int index = path.IndexOf(Path.DirectorySeparatorChar);
String directoryName = (index < 0) ? path : path.Substring(0, index);
String otherName = (index < 0) ? null : path.Substring(index + 1);
TreeNode childNode = parent.Nodes.Add(directoryName);
PopulateTree(otherName, childNode, depth - 1);
}
In order to load a collection of paths without any restriction with possible common nodes you can use
something like this:
private void PopulateTree(String path, TreeView view, TreeNode parent) {
if (String.IsNullOrEmpty(path))
return;
int index = path.IndexOf(Path.DirectorySeparatorChar);
String directoryName = (index < 0) ? path : path.Substring(0, index);
String otherName = (index < 0) ? null : path.Substring(index + 1);
TreeNode childNode = null;
TreeNodeCollection nodes = (parent == null) ? view.Nodes : parent.Nodes;
foreach (TreeNode node in nodes)
if (String.Equals(node.Name, directoryName)) {
childNode = node;
break;
}
if (childNode == null)
childNode = nodes.Add(directoryName);
PopulateTree(otherName, view, childNode);
}
private void PopulateTree(IEnumerable<String> paths, TreeView view) {
view.BeginUpdate();
try {
foreach (String path in paths)
PopulateTree(path, view, null);
}
finally {
view.EndUpdate();
}
}
...
PopulateTree(ListWithPaths, MyTreeView)

Treeview in web form check child nodes on parent node check

Im using Treeview control of System.Web.UI class, to display Category and subcategory of an item.
I have tried the following code but no hope
protected void tvwOrganisation_TreeNodeCheckChanged(object sender, TreeNodeEventArgs e)
{
if (tvwOrganisation.CheckedNodes.Count > 0)
{
// the selected nodes.
foreach (TreeNode node in tvwOrganisation.CheckedNodes)
{
if (node.ChildNodes.Count > 0)
{
foreach (TreeNode childNode in node.ChildNodes)
{
childNode.Checked = true;
}
}
}
}
}
Is there a way I can do this, I have tried javascript too.
Also what is the replace of AfterCheck - windows formd event in web forms.
The tree tag was as follows,
<asp:TreeView ID="tvwRegionCountry" runat="server" ShowCheckBoxes="All" ExpandDepth="0" AfterClientCheck="CheckChildNodes();" PopulateNodesFromClient="true" ShowLines="true" ShowExpandCollapse="true" OnTreeNodeCheckChanged="tvwRegionCountry_TreeNodeCheckChanged"
onclick="OnTreeClick(event)">
</asp:TreeView>
Added following JS as mentioned in asp.net treeview checkbox selection
<script language="javascript" type="text/javascript">
function OnTreeClick(evt) {
var src = window.event != window.undefined ? window.event.srcElement : evt.target;
var isChkBoxClick = (src.tagName.toLowerCase() == "input" && src.type == "checkbox");
if (isChkBoxClick) {
var parentTable = GetParentByTagName("table", src);
var nxtSibling = parentTable.nextSibling;
if (nxtSibling && nxtSibling.nodeType == 1)//check if nxt sibling is not null & is an element node
{
if (nxtSibling.tagName.toLowerCase() == "div") //if node has children
{
//check or uncheck children at all levels
CheckUncheckChildren(parentTable.nextSibling, src.checked);
}
}
//check or uncheck parents at all levels
CheckUncheckParents(src, src.checked);
}
}
function CheckUncheckChildren(childContainer, check) {
var childChkBoxes = childContainer.getElementsByTagName("input");
var childChkBoxCount = childChkBoxes.length;
for (var i = 0; i < childChkBoxCount; i++) {
childChkBoxes[i].checked = check;
}
}
function CheckUncheckParents(srcChild, check) {
var parentDiv = GetParentByTagName("div", srcChild);
var parentNodeTable = parentDiv.previousSibling;
if (parentNodeTable) {
var checkUncheckSwitch;
if (check) //checkbox checked
{
var isAllSiblingsChecked = AreAllSiblingsChecked(srcChild);
if (isAllSiblingsChecked)
checkUncheckSwitch = true;
else
return; //do not need to check parent if any(one or more) child not checked
}
else //checkbox unchecked
{
checkUncheckSwitch = false;
}
var inpElemsInParentTable = parentNodeTable.getElementsByTagName("input");
if (inpElemsInParentTable.length > 0) {
var parentNodeChkBox = inpElemsInParentTable[0];
parentNodeChkBox.checked = checkUncheckSwitch;
//do the same recursively
CheckUncheckParents(parentNodeChkBox, checkUncheckSwitch);
}
}
}
function AreAllSiblingsChecked(chkBox) {
var parentDiv = GetParentByTagName("div", chkBox);
var childCount = parentDiv.childNodes.length;
for (var i = 0; i < childCount; i++) {
if (parentDiv.childNodes[i].nodeType == 1) //check if the child node is an element node
{
if (parentDiv.childNodes[i].tagName.toLowerCase() == "table") {
var prevChkBox = parentDiv.childNodes[i].getElementsByTagName("input")[0];
//if any of sibling nodes are not checked, return false
if (!prevChkBox.checked) {
return false;
}
}
}
}
return true;
}
//utility function to get the container of an element by tagname
function GetParentByTagName(parentTagName, childElementObj) {
var parent = childElementObj.parentNode;
while (parent.tagName.toLowerCase() != parentTagName.toLowerCase()) {
parent = parent.parentNode;
}
return parent;
}
</script>
and it worked...

Categories

Resources