If the logic within this method is run from an event handler such as Button_Click it works perfectly, but, when running this from a method such as below I get the error:
hostView.SelectedNode.Nodes.Add(newNode);
Object reference not set to an instance of an object.
Here is my code:
private void SetupHostTree()
{
// Set internal host names
using (var reader = File.OpenText("Configuration.ini"))
{
List<string> hostnames = ParseInternalHosts(reader).ToList();
foreach (string s in hostnames)
{
TreeNode newNode = new TreeNode(s);
hostView.SelectedNode.Nodes.Add(newNode);
string title = s;
TabPage myTabPage = new TabPage(title);
myTabPage.Name = s;
tabControl1.TabPages.Add(myTabPage);
}
}
}
Maybe there are no Selected Nodes :)
Probably because no node is currently selected in the hostView TreeView.
The documentation says that the TreeView.SelectedNode property will return null when no node is currently selected. And since you've combined it into an expression, the entire expression is failing because there is no Nodes collection on a null object!
Try this code:
private void SetupHostTree()
{
// Set internal host names
using (var reader = File.OpenText("Configuration.ini"))
{
List<string> hostnames = ParseInternalHosts(reader).ToList();
foreach (string s in hostnames)
{
// Ensure that a node is currently selected
TreeNode selectedNode = hostView.SelectedNode;
if (selectedNode != null)
{
TreeNode newNode = new TreeNode(s);
selectedNode.Nodes.Add(newNode);
}
else
{
// maybe do nothing, or maybe add the new node to the root
}
string title = s;
TabPage myTabPage = new TabPage(title);
myTabPage.Name = s;
tabControl1.TabPages.Add(myTabPage);
}
}
}
Related
I get data from tow database, db1,db2, then Now I want to create treeView for the data in the resulting datagridview; in datagrid view there are: id, name, director,the first record is the prim director, that mean he has not up director(he is owner), each record has no other record or has more records(child), and each child has grandchild and so on, this scenario Just Like in the this page:
I want to create treeview (parent and child and grandchild and so on), depending on xml file
when i used this snippet after some :
void setTree()
{
{
foreach(DataGridViewRow dt in DataGridView1.Rows)
{
var per = this.DataGridView1.Rows.Cast<DataGridViewRow>().Select(n => new person
{
name = dt.Cells[0].Value.ToString(),
Sex = dt.Cells[1].Value.ToString(),
Status = dt.Cells[2].Value.ToString(),
child = dt.Cells[3].Value.ToString(),
id = dt.Cells[4].Value.ToString(),
father = dt.Cells[5].Value.ToString()
}).ToList();
var rootTreeNode = GetTree(per, "").First();.........(1)
treeView1.Nodes.Add(rootTreeNode);
}
}
}
private TreeNode[] GetTree(List<person> per, string parent)
{
return per.Where(p => p.father == parent).Select(p =>
{
var node = new TreeNode(p.name);
node.Tag = p.id;
node.Nodes.AddRange(GetTree(per, p.id));
return node;
}).ToArray();
}
Now, when I use this code, I get error at mark(1),it say:Additional information: Sequence contains no elements.
thank you
after several readings in internet and attempts to solve this small problem, I successed finally.
this is the solution:
{
.............
TreeNode tn = new TreeNode(this.DataGridView2.Rows[0].Cells[0].Value.ToString());//text
tn.Tag = this.DataGridView2.Rows[0].Cells[4].Value.ToString();// id
tn.Name = this.DataGridView2.Rows[0].Cells[5].Value.ToString();//directorid
treeView1.Nodes.Add(tn);
settree(tn);
}
public void settree(TreeNode ns)
{
foreach (DataGridViewRow dr in DataGridView2.Rows)
{
if (dr.Cells[5].Value.ToString() == ns.Tag.ToString())
{
TreeNode tsn = new TreeNode(dr.Cells[0].Value.ToString());
tsn.Tag = dr.Cells[4].Value.ToString();
tsn.Name = dr.Cells[5].Value.ToString();
ns.Nodes.Add(tsn);
settree(tsn);
}
}
}
i will be happy if you benefit from this code.
I built a code that takes data from an online database and adds them recursively through a while loop in a TreeView. Substantially the Add function is called when the user selects a new nation in the tree, for example, this is what is contained in the TreeView (Available countries):
<TreeView Name="nation_team" SelectedItemChanged="nation_team_SelectionChanged">
<TreeViewItem Header="Italy"/>
<TreeViewItem Header="Germany"/>
</TreeView>
when the user selects for example Italy, then the following function is set in motion:
private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
soccerSeason.getChampionshipsForTeams();
}
the following function contains this content:
string stm = #" SELECT * FROM league
WHERE country = '" + MainWindow.AppWindow.nation_team.SelectedValue.ToString() + "'";
MySqlCommand cmd = new MySqlCommand(stm, database.Connection);
MySqlDataReader rdr = cmd.ExecuteReader();
TreeViewItem rootNode = new TreeViewItem() { Header = MainWindow.AppWindow.nation_team.SelectedValue.ToString() };
while (rdr.Read())
{
rootNode.Items.Add(getTreeViewChampionships(rdr.GetString(3)));
MainWindow.AppWindow.nation_team.Items.Add(rootNode);
}
rdr.Close();
As you can see I run a query to download all the championships for the nation selected, that is precisely the value taken from the TreeView (Italy or Germany).
Now I run the query and execute the reader "RDR".
Then I declare a rootNode that corresponds to the country selected by the user, in this country you have to add the championships returned from Query, if the user select "Italy", I'm waiting this result structure in TreeView:
Italy
Serie A //this two values was returned by query
Serie B
So far no problem query is successful and the values are read.
At this point it is activated while loop that loops through all the values, inside the while loop we find this method:
rootNode.Items.Add(getTreeViewChampionships(rdr.GetString(3)));
that would add "Serie A and Serie B" to Italy. The method getTreeViewChampionships, the method receives as a parameter the championships they are reading "RDR", in particular "Series A" and "Series B".
private TreeViewItem getTreeViewChampionships(string campionato)
{
TreeViewItem item = new TreeViewItem() { Header = campionato };
return item;
}
It would seem that there should be no problems and yet whenever I select a nation comes back the following error on this line:
MainWindow.AppWindow.nation_team.Items.Add(rootNode);
System.InvalidOperationException: For the item already exists a logical parent element. You must disassociate it from the old parent before it can bind to a new parent.
in MS.Internal.Controls.InnerItemCollectionView.AssertPristineModelChild (Object item)
in MS.Internal.Controls.InnerItemCollectionView.Add (Object item)
in System.Windows.Controls.ItemCollection.Add (Object newItem)
What am I doing wrong?
NB: The Nation available in the XAML is just an example, I add the Nations behind the code, like this way:
TreeViewItem rootNode = new TreeViewItem() { Header = rdr.GetStringOrNull(0) };
MainWindow.AppWindow.nation_team.Items.Add(rootNode);
First Answer
I managed to reproduce your problem with that minimal code :
private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
TreeViewItem rootNode = new TreeViewItem() { Header = nation_team.SelectedValue.ToString() };
for (int i = 0; i < 3; ++i)
{
rootNode.Items.Add(new TreeViewItem() { Header = "some data" });
nation_team.Items.Add(rootNode);
}
}
This is how to resolve your problem :
private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
TreeViewItem rootNode = (TreeViewItem)e.NewValue;
for (int i = 0; i < 3; ++i)
{
rootNode.Items.Add(new TreeViewItem() { Header = "some data" });
}
}
In that code, you won't create a new TreeViewItem with the same header as the selected item. You just get the actual selected item (i.e. e.NewValue) so you can directly add what you want.
Result on click :
Hope that helped.
Answer to comment
In order to dissociate root nodes (i.e. countries) and child nodes (i.e. series), I suggest something like that :
TreeViewItem rootNode = (TreeViewItem)e.NewValue;
if (rootNode.Parent is TreeView)
{
//Country
}
else
{
//Serie
}
If the parent type is TreeView, then the node is a root node and you can get the data from your database. If not, you are on a child node, and you can do other stuff.
Edit after context changed
I can't reproduce your issue. I used an empty TreeView in XAML code, then that code-behind :
public MainWindow()
{
InitializeComponent();
var rootNode1 = new TreeViewItem() { Header = "Italy" };
var rootNode2 = new TreeViewItem() { Header = "Germany" };
nation_team.Items.Add(rootNode1);
nation_team.Items.Add(rootNode2);
}
private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
TreeViewItem rootNode = (TreeViewItem)e.NewValue;
for (int i = 0; i < 3; ++i)
{
rootNode.Items.Add(new TreeViewItem() { Header = "some data" });
}
}
All worked as excepted. e.NewValue is not null. Are you sure you are doing it the same way ?
Using C#, I have created a program that executes a command line perl script and captures the output to a text file. The output is from ClearCase and was a huge pain to figure out, there isnt much in the way of documentation of the ClearCase plugin.
Anyhow now what I would like to do is skip the file and only use the output from the console...
The output appears like
"\Directory\subDirectory\subsubDir\etc\dir\##main\branch\version\4"
"\Directory\subDirectory\subsubDir\etc\dir\somefile.txt##main\branch\version\3"
"\Directory\subDirectory\subsubDir\etc\dir\somefile.txt##\branch\version\1"
I then want to basically load that into a tree view. So that the tree appears as a directory listing...that could be sortable so it is easy to tell the latest version of any particular file or directory.
One problem is there are multiple instances of the same directory and files as each version of a particular file is counted and there may be different branches and versions...
I have trouble because I am only slightly experienced with C# and I can't quite comprehend how to load arrays in arrays then have it neatly go to a dynamic tree view (keeping its associations).
Most online examples for tree views I find have hard coded strings, not dynamic strings[].
Does anyone have any experience doing this? Or know of any tricks? I cant decide if Visual Studio's line editing is best to use to split the directories or to use a regex...I will at a later point (once I get this figured out) want to Re-send this data into clearcase via command prompt to auto checkout these associated files...but that part seems easier from this point of view...
I can't post the code that I have, closed loop lan only.
The example of treeview that I've been scratching my head on is from DotNetPerls :
private void Form1_Load(object sender, EventArgs e)
{
//
// This is the first node in the view.
//
TreeNode treeNode = new TreeNode("Windows");
treeView1.Nodes.Add(treeNode);
//
// Another node following the first node.
//
treeNode = new TreeNode("Linux");
treeView1.Nodes.Add(treeNode);
//
// Create two child nodes and put them in an array.
// ... Add the third node, and specify these as its children.
//
TreeNode node2 = new TreeNode("C#");
TreeNode node3 = new TreeNode("VB.NET");
TreeNode[] array = new TreeNode[] { node2, node3 };
//
// Final node.
//
treeNode = new TreeNode("Dot Net Perls", array);
treeView1.Nodes.Add(treeNode);
and for arrays to tree from D.Morton # MSDN
public void AddTreeViewItem(string[] item)
{
TreeNodeCollection nodes = treeView1.Nodes;
for (int i = 0; i < item.Length; i++)
nodes = nodes.Find(item[i], false).Length > 0 ? nodes.Find(item[i], false)
[0]. Nodes : nodes.Add(item[i], item[i]).Nodes;
}
The TreeBuilder class below will build a proper tree for you. I've tested it with your examples and it works. Where there are gaps in the tree it will recursively trim the path to create the missing parent nodes and then unwind to add the item itself. The TreeBuilder breaks the problem into handling file paths and version paths by splitting your lines at the ##. It treats the version path as a child of the file path. This allows the built in Path.GetFileName and Path.GetDirectoryName functions to be used to label the nodes and trim the paths to find parents.
using System;
using System.Windows.Forms;
using System.IO;
public class TreeBuilder
{
public TreeBuilder()
{
TreeNode rootNode = new TreeNode(#"\");
rootNode.Name = #"\";
RootNode = rootNode;
}
public TreeNode RootNode
{
get;
set;
}
public void AddItems(string[] items)
{
Array.Sort(items);
if (string.IsNullOrEmpty(RootNode.Name))
{
RootNode.Name = #"\";
}
foreach (string item in items)
{
string[] itemParts = item.Split(new string[] { "##" }, StringSplitOptions.None);
string filePath = itemParts[0].TrimEnd('\\');
string versionPath = itemParts[1];
TreeNode fileNode = AddNode(RootNode, filePath);
TreeNode versionNode = AddNode(fileNode, filePath + "##", versionPath);
}
}
public TreeNode AddNode(TreeNode topNode, string path)
{
return AddNode(topNode, null, path);
}
public TreeNode AddNode(TreeNode topNode, string pathPrefix, string path)
{
pathPrefix = pathPrefix ?? string.Empty;
TreeNode node = null;
if (!string.IsNullOrEmpty(path) && topNode.Name != path)
{
string parentPath = Path.GetDirectoryName(path);
TreeNode[] matchingNodes = topNode.Nodes.Find(pathPrefix + path, true);
if (matchingNodes == null || matchingNodes.Length == 0)
{
string nodeLabel = Path.GetFileName(path);
nodeLabel = string.IsNullOrEmpty(nodeLabel) ? #"\" : nodeLabel;
node = new TreeNode(nodeLabel);
node.Name = pathPrefix + path;
TreeNode[] parentNodes = topNode.Nodes.Find(pathPrefix + parentPath, true);
TreeNode parentNode = null;
if (parentNodes != null && parentNodes.Length > 0)
{
parentNode = parentNodes[0];
parentNode.Nodes.Add(node);
}
else
{
parentNode = AddNode(topNode, pathPrefix, parentPath);
parentNode.Nodes.Add(node);
}
}
else
{
node = matchingNodes[0];
}
}
else
{
node = topNode;
}
return node;
}
}
Here's an example of how you'd use it in a form with a TreeView on it:
private void Form1_Load(object sender, EventArgs e)
{
string[] fileStrings = new String[]
{
#"\Directory\subDirectory\subsubDir\etc\dir\##main\branch\version\4",
#"\Directory\subDirectory\subsubDir\etc\dir\somefile.txt##main\branch\version\3",
#"\Directory\subDirectory\subsubDir\etc\dir\somefile.txt##\branch\version\1"
};
TreeBuilder treeBuilder = new TreeBuilder();
treeBuilder.AddItems(fileStrings);
treeView1.Nodes.Add(treeBuilder.RootNode);
treeView1.ExpandAll();
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
TreeNode selectedNode = treeView1.SelectedNode;
MessageBox.Show(string.Format("Label: {0}\nClearCase path: {1}\nTree path: {2}", selectedNode.Text, selectedNode.Name, selectedNode.FullPath));
}
One of possible solutions could be split the string by directories:
string[] directories = "\Directory\subDirectory\subsubDir\etc\dir\##main\branch\version\4".Split(Path.DirectorySeparatorChar);
after have a Dictionary<string, List<string>> tree, where key is a Directory path, and List<string> a list of directories or files of "key" directory.
If it's not something you're searching for, please clarify.
Is there a way I can keep the text of a Parent node but remove the link? The treeview parent node is used just as a header, no navigation. Any help would be great. Thanks.
private void BindNodes(string PtID)
{
if (PtID != "")
{
int PatientID = Convert.ToInt32(PtID);
DBConnection dbObj = new DBConnection();
if (Session["Activepatient"] != null)
{
string[] SubChild = new string[4];
SubChild[0] = "Demographics";
SubChild[1] = "Medication Reviews";
SubChild[2] = "Drug Testing & Monitoring";
SubChild[3] = "Other Program";
TreeNode oTrParent = new TreeNode();
//trv_patient.ParentNodeStyle = "None";
//oTrParent.SelectAction.Style.Add("display", "none");
TreeNode oTrSubChild1;
TreeNode oTrSubChild;
for (int i = 0; i < 4; i++)
{
oTrSubChild1 = new TreeNode();
oTrSubChild1.Text = SubChild[i];
if (i == 1)
{
PatientInfoCollection patientCollection = new PatientInfoCollection();
patientCollection = dbObj.GetMedicationReviews(PatientID);
foreach (PatientInfo au in patientCollection)
{
oTrSubChild = new TreeNode();
PatientInfo Patient = new PatientInfo();
oTrSubChild.Text = au.DateRcvd.Value.ToString("MM-dd-yyyy")
oTrSubChild.Target = au.ReviewId.ToString();
oTrSubChild1.ChildNodes.Add(oTrSubChild);
}
oTrSubChild = new TreeNode();
oTrSubChild.Text = "Add Medication Review";
oTrSubChild.Target = "New";
oTrSubChild1.ChildNodes.Add(oTrSubChild);
}
trv_patient.Nodes.Add(oTrSubChild1);
}
}
}
}
If temp is such node whose text you want to be plain text and not link then use code below.
TreeNode temp = new TreeNode("text");
temp.SelectAction = TreeNodeSelectAction.None;
treeView1.Nodes.Add(temp);
This is what your looking for. You have to set the SelectAction of the parent node TreeNode to TreeNodeSelectAction.None. I even show how to do it with the child too.
ASP.NET
<asp:TreeView
ID="MyTreeView"
ShowCheckBoxes="Parent,Leaf,All"
runat="server"
ShowLines="true"
ShowExpandCollapse="true">
</asp:TreeView>
C#
//Make A Parent Node
var Parent = new TreeNode();
Parent.Text = "Parent 1";
// Make the parent nodes not be hyperlinks but plain text
Parent.SelectAction = TreeNodeSelectAction.None;
//You can do the same with a child node like so
var Child = new TreeNode();
Child.Text = "Child 1";
// Make the child nodes not be hyperlinks but plain text
Child.SelectAction = TreeNodeSelectAction.None;
//Add the child node to the parent node
Parent.ChildNodes.Add(Child);
//Finally add the parent node with children to the treeview
MyTreeView.Nodes.Add(Parent);
I'm not sure if I understand what you want. Assuming that it's WinForms and that you just want to disable the ability to select the root node in a TreeView you could just handle the BeforeSelect event of the TreeView and then have the following code:
if (e.Node.Parent == null)
e.Cancel = true;
TreeNode root = new TreeNode("Root");
root.SelectAction = TreeNodeSelectAction.None;
Im working with file systems and I have a List<> of file objects that have the file path as a property. Basically I need to create a treeview in .NET but im struggling to think of the best way to go about doing this as I need to create a tree structure from a list like:
C:/WINDOWS/Temp/ErrorLog.txt
C:/Program Files/FileZilla/GPL.html
C:/Documents and Settings/Administrator/ntuser.dat.LOG
etc....
The list is not structured at all and I cant make any changes to the current object structure.
I'm working in C#.
Many thanks for all who contribute
If you wanted to stick with the strings something like this would work...
TreeNode root = new TreeNode();
TreeNode node = root;
treeView1.Nodes.Add(root);
foreach (string filePath in myList) // myList is your list of paths
{
node = root;
foreach (string pathBits in filePath.Split('/'))
{
node = AddNode(node, pathBits);
}
}
private TreeNode AddNode(TreeNode node, string key)
{
if (node.Nodes.ContainsKey(key))
{
return node.Nodes[key];
}
else
{
return node.Nodes.Add(key, key);
}
}
I would turn the string into a FileInfo.
Once you have the FileInfo object, you can use the Directory property to retrieve the DirectoryInfo for each path.
Once you have the DirectoryInfo for the path, it's easy to "walk up" the Parent reference in DirectoryInfo to turn each path into a list of directories + filename - ie:
{"C:","Windows","Temp","ErrorLog.txt"}
This should be fairly straightforward to insert into your treeview. Just look for each section of the path in turn, and if it doesn't exist, add it....
give recursion a try.
private void AddFiles()
{
// Iterate your list with FileInfos here
foreach( var fileInfo in new Collection<FileInfo>() )
{
GetOrCreateTreeNode( fileInfo.Directory ).Nodes.Add( new TreeNode( fileInfo.Name ) );
}
}
private TreeNode GetOrCreateTreeNode( DirectoryInfo directory )
{
if( directory.Parent == null )
{
// Access your TreeView control here:
var rootNode = <TreeView>.Nodes[directory.Name];
if( rootNode == null )
{
rootNode = new TreeNode(directory.Name);
// Access your TreeView control here:
<TreeView>.Nodes.Add( rootNode );
}
return rootNode;
}
var parent = GetOrCreateTreeNode( directory.Parent );
var node = parent.Nodes[directory.Name];
if( node == null )
{
node = new DirectoryNode( directory );
parent.Nodes.Add( node );
}
return node;
}
This code should give you only an idea - I have to admit that I did not test it before posting 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];
}
}
}
EHosca's piece worked for me perfectly, with one change - I had to set lastnode to nothing after the foreach path in paths area.
This is eHosca's code above, ported to VB.
Private Sub PopulateTreeView(tv As TreeView, paths As List(Of String), pathSeparator As Char)
Dim lastnode As TreeNode = Nothing
Dim subPathAgg As String
For Each path In paths
subPathAgg = String.Empty
lastnode = Nothing
For Each subPath In path.Split(pathSeparator)
subPathAgg += subPath + pathSeparator
Dim nodes() As TreeNode = tv.Nodes.Find(subPathAgg, True)
If nodes.Length = 0 Then
If IsNothing(lastnode) Then
lastnode = tv.Nodes.Add(subPathAgg, subPath)
Else
lastnode = lastnode.Nodes.Add(subPathAgg, subPath)
End If
Else
lastnode = nodes(0)
End If
Next
Next
End Sub