SelectedNode is not working after refresh always showing null - c#

Here i am trying to show the last selected node after reload of treeview but the selected node is always null. I am able to find the tree node from the treeview node collection but not able to assign it to tree view. Please suggeest:
public void LoadTreeViewData()
{
treeView.Nodes.Clear();// Clear any existing items
treeView.BeginUpdate(); // prevent overhead and flicker
LoadBaseNodes();//Populate all nodes
treeView.EndUpdate();
treeView.Refresh();
treeView.ExpandAll();
if (!string.IsNullOrEmpty(m_oSelectedNode_NAME))
{
TreeNode[] treeNodes = treeView.FlattenTree()
.Cast<TreeNode>()
.Where(r => Convert.ToDecimal(r.Tag) == Convert.ToDecimal(m_oSelectedNode_NAME))
.ToArray();
treeView.SelectedNode = treeNodes[0];
treeView.Focus();
}
}

This problem is happening because i am trying to Update the selected node inside the Tree view after label edit event. I put a timer inside After label edit to resolve the issue and set the Selected node it works for me.
var tnm = new Timer() { Enabled = true, Interval = 30 };
tnm.Tick += delegate {
SetSelectioNode();
tnm.Dispose();
};

Related

Referencing the TreeView from other TreeViews

I have a window form that has a control treeViewMain and in the code I have a list of treeViews that has variable number of treeViews. I want the treeViewMain to show anyone of the treeView from the list.
treeViewMain=treeViews[0];
but the form is not showing the tree. Also I have thoroughly checked the treeViews in the list, they are populating correctly.
Apparently simple assigning does not work. According to this post it seems that the parent of a TreeViewNode has to be unique and there by the "fruit" can only sit at one tree.
One workaround could be to set the parent property of the TreeView in your list to the treeViewMain:
treeViews[0].Parent = treeViewMain;
this will put the treeview from the list as a child inside treeViewMain. If you want to change that and load the next item from your list you need to make sure that the previously loaded item's parent property is set to null before assigning a new parent like in this example:
private int count = 0;
private void button_ChooseTreeView_Click(object sender, EventArgs e)
{
if (count > 0)
{
treeViews[count -1].Parent = null;
}
treeViews[count].Parent = treeViewMain;
count++;
}
The other possibility would be to clone each node and populate the treeViewMain each time you want to update the list items to the display

Populating a treeview from a list

At the moment I have a hardcoded treeview in a winform set up with the following code:
private void Form1_Load_1(object sender, EventArgs e)
{
TreeNode _leftCameraNode = new TreeNode("LeftCamera");
TreeNode _rightCameraNode = new TreeNode("RightCamera");
TreeNode[] stereoCameraArray = new TreeNode[] { _leftCameraNode, _rightCameraNode };
TreeNode _screenNode = new TreeNode("Screen");
TreeNode _cameraNode = new TreeNode("Camera", stereoCameraArray);
TreeNode[] headNodeArray = new TreeNode[] { _cameraNode };
TreeNode _headNode = new TreeNode("HeadNode", headNodeArray);
TreeNode[] centreNodeArray = new TreeNode[] { _screenNode, _headNode };
TreeNode _centreNode = new TreeNode("CentreNode", centreNodeArray);
// root node
TreeNode[] inmoRootNodeArray = new TreeNode[] { _centreNode };
TreeNode treeNode = new TreeNode("Main Node", inmoRootNodeArray);
treeView1.Nodes.Add(treeNode);
}
This works fine, however it is very limiting in its functionality. What I really want this to do is be populated from a list of nodes that I've set up and filled out with information that I'm getting from a bunch of text boxes on my form.
For example, I create a new list of screens (child of my node class) like so:
public List<HV_Screen> _screenList = new List<HV_Screen>();
Then I fill out my list with the data entered from my text box like this:
if (_selectedNode > -1)
{
Node n = _nodeList[_nodeList.Count - 1];
n.Name = _screenName;
}
I've been looking around on the net and on stackoverflow but I can't find anything to help me out with dynamically creating my treeview, so I was wondering if anyone would be able to point me in the right direction and help me out in how to do this?
The reason I want to do this is because, say I have 3 different instances of my screen, I want my treeview to show this, Then if I change the name in screen1 to MYSCREEN, I want my treeview to show this. But, should I click screen2, the treeview will still show the default name. Then, when I click back on screen1, its new name MYSCREEN will still be there on display.
I hope that makes sence.
Edit
Following on from a comment here is a screenshot of my current GUI:
The tree structure there has all be hard coded in with the code above. This takes in no information from my class screen class.
Now, my HV_Screen class looks as follows:
private string WIDTH;
private string HEIGHT;
public string Width
{
get { return WIDTH; }
set { WIDTH = value; }
}
public string Height
{
get { return HEIGHT; }
set { HEIGHT = value; }
}
public override List<XmlElement> GenerateXML(XmlDocument _xmlDoc)
{
List<XmlElement> elementList = new List<XmlElement>();
XmlElement _screenName = _xmlDoc.CreateElement("ScreenName");
_screenName.SetAttribute("Name", name.ToString());
_screenName.InnerText = name.ToString();
elementList.Add(_screenName);
XmlElement _screenTag = _xmlDoc.CreateElement("ScreenTag");
_screenTag.SetAttribute("Tag", tag.ToString());
_screenTag.InnerText = tag.ToString();
elementList.Add(_screenTag);
XmlElement _localPosition = _xmlDoc.CreateElement("LocalPosition");
_localPosition.SetAttribute("X", XPOS.ToString());
_localPosition.SetAttribute("Y", YPOS.ToString());
_localPosition.SetAttribute("Z", ZPOS.ToString());
_localPosition.InnerText = WorldPos.ToString();
elementList.Add(_localPosition);
XmlElement _orientation = _xmlDoc.CreateElement("Orientation");
_orientation.SetAttribute("Yaw", YAW.ToString());
_orientation.SetAttribute("Pitch", PITCH.ToString());
_orientation.SetAttribute("Roll", ROLL.ToString());
_orientation.InnerText = Orientation.ToString();
elementList.Add(_orientation);
XmlElement _width = _xmlDoc.CreateElement("Width");
_width.SetAttribute("Width", WIDTH.ToString());
_width.InnerText = WIDTH.ToString();
elementList.Add(_width);
XmlElement _height = _xmlDoc.CreateElement("Height");
_height.SetAttribute("Height", HEIGHT.ToString());
_height.InnerText = HEIGHT.ToString();
elementList.Add(_height);
return elementList;
}
Nothing too major. This simply takes in the information and writes it to an xml file. I plan on doing this for each of my Node children. So, if I was to have a camera class, it would have its own generate XML function and write it out from there. My base class (node) simply has a bunch of getters and setters for things like name, tag etc.
With the way the code is set up at the moment, I can add in new nodes. First I must select the root node I want to branch from, then I fill out the information associated with it. So in that screen shot, if I was to select Main Node and then hit the Add button, Sample Name would now be a child of Main Node. However, if I was to select Sample and Name and change it, nothing would happen.
This way is also hard coded in to only relate to my screen class. In theory, I could simply turn a lot of different text boxes on and off but this would be really bad practise. And I'm pretty sure it will have an impact on my programs performance.
So again, what I want is one Name text box that will be in charge of filling out the name for every object that requires a name. Then, I wish to take the name I entered and have it fill out the treeview. Once I select it, I want my selected node to fill out the textboxes with all of the associated text I put in for it. But, should I change the name of my selected node, it will also change the name in the tree structure.
Again, sorry if that is confusing. I'm pretty beat at the moment.

Checking a Checkbox after checking another one (TreeView)

So i have this TreeView with 3 parent nodes, each one with some childs. There's a specific child that depends on others two childs in the same parent node. Here's the code i've done:
private void tvMorgan_AfterCheck(object sender, TreeViewEventArgs e)
{
if ((e.Node.Text.Contains("BRL/EUR")) && (e.Node.Parent.Text.Contains("FWD")))
{
TreeNode tnParent = e.Node.Parent;
tnParent.Nodes["BRL/USD"].Checked = true;
tnParent.Nodes["EUR/USD"].Checked = true;
}
}
When i run it, it can't find those two nodes i want to check.
Thanks in advance
As commentors pointed out, your nodes are most likely missing a name, which is the key used in the string index lookup. Easy to happen since most nodes get created at runtime.
Simple way to add the name:
myParent.Nodes.Add(new TreeNode("BRL/USD") { Name = "BRL/USD" });
myParent.Nodes.Add(new TreeNode("EUR/USD") { Name = "EUR/USD" });
Then your code should work:
if (tnParent.Nodes.ContainsKey("EUR/USD"))
tnParent.Nodes["EUR/USD"].Checked = true;
You should probably use the same logic on your if condition so that you are less reliant on the text property, which really should be only used for display purposes:
if ((e.Node.Name == "BRL/EUR") ...
If not setting the names, then you would have to search the node tree yourself to find the "text":
TreeNode found = tnParent.Nodes.OfType<TreeNode>().Where(x => x.Text.Contains("EUR/USD")).First();
if (found != null)
found.Checked = true;

WinForms TreeView - how to manually "highlight" node (like it was clicked)

I would need to know how to let the programatically selected node make graphically in the state "selected" like the user clicked on it. SelectedNode only makes this one internally selected. Thank you very much!
The reason it does not show as highlighted is due to the tree view not having focus. This is in a button click event on my test form:
TreeView1.SelectedNode = TreeView1.Nodes(2);
TreeView1.Focus();
Which highlights the node properly. if you remove the Focus(); call it doesn't highlight until you click into the tree view (anywhere in the tree view, not necessarily on to the node that you want to be selected).
TreeView1.SelectedNode.BackColor = SystemColors.HighlightText; // This will work
Above solutions will only set the focus on it but will not change the highlight view of it.
This works for me for .net 3.5:
Set the treeview component's DrawMode property to: OwnerDrawAll
Then in the DrawNode event write the following:
if (((e.State & TreeNodeStates.Selected) != 0) && (!MyTreeView.Focused))
e.Node.ForeColor = Color.Blue;
else
e.DrawDefault = true;
And in the BeforeSelect event have:
if (MyTreeView.SelectedNode != null)
MyTreeView.SelectedNode.ForeColor = Color.Black;
e.Node.ForeColor = Color.Blue;
I don't know if it helps you or not but check the taborder of the the page and make sure that the tree view control has tab order of 0
Here is what I got to work:
void myProcedure()
{
// Hookup a DrawMode Event Handler
this.myTV.DrawNode += myTV_DrawNode;
// Set DrawMode and HideSelection
this.myTV.DrawMode = TreeViewDrawMode.OwnerDrawText;
this.myTV.HideSelection = false;
// Make sure the TreeView has Focus
this.myTV.Focus();
// Make sure the TreeView is Selected
this.myTV.Select();
// If the TreeView has a Node, I want to select the first Node to demonstrate.
if (this.myTV.Nodes.Count > 0)
{
// Make sure the node is visible
this.myTV.Nodes[0].EnsureVisible();
// Make sure the Node is Selected
this.myTV.SelectedNode = myTV.Nodes[0];
}
// Make sure the SelectedNode IS the Node that we programmatically want to select.
textBox1.Text = this.myTV.SelectedNode.Text;
// if we display sanityCheck1 string, it actually is the correct node.text
// Make sure .NET runtime knows the Node is selected
textBox1.Text += " is Selected = " + this.myTV.SelectedNode.IsSelected.ToString();
}
Following up: laalto answered the How to HighLight the TreeView.Node. The following code in the DrawNode Event Handler, from samball's answer, properly highlights the TreeView.Node based on its Selected State.
private void myTV_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
// first, let .NET draw the Node with its defaults
e.DrawDefault = true;
// Now update the highlighting or not
if (e.State == TreeNodeStates.Selected)
{
e.Node.BackColor = SystemColors.Highlight;
e.Node.ForeColor = SystemColors.HighlightText;
}
else
{
e.Node.BackColor = ((TreeView)sender).BackColor;
e.Node.ForeColor = ((TreeView)sender).ForeColor;
}
}
Platform = C# .NET 4.5 in Windows 10, Visual Studio 2015
TreeView1.SelectedNode = TreeView1.Nodes(2);
this.ActiveControl = TreeView1;
This works for me (.net 4.7)
The underlying Win32 control supports this (think it's TVIS_DROPHILITED), but I can't see the same functionality exposed through the TreeView control.
As theraneman says, you could fake it with the TreeNode.ForeColor and BackColor properties...
I had an similar issue and wanted to have a TreeView node selected (highlighted) on form load.
Maybe someone has the same problem, too.
I first tried Pondidum's solution. Without success.
But then I found the solution in another thread: Simply set the TabIndex of the TreeView to 0.
In that case you don't need to set the focus. Just choose the node that should be selected by using SelectedNode and set the TabIndex. That's it.
Not sure, but can you not change the background color of that node?

TreeView child node populating problem

I need to construct a huge treeview from a composite database table with Grouping.
Grouping is, what we see in SQL Server Management Studio Express. After a Database node, some fixed folders are shown (like, Database Diagrams, Tables, Views, Synonyms, Programmability and Security) and children are grouped in those folders.
Up to this point I have used AfterSelect event and handler to achieve this.
But the problem with AfterSelect is, before selecting the node, the viewer is not able to know whether there is any child available. This is because, the expandable plus sign is not visible.
I want to use BeforeExpand. But the problem with BeforeExpand is, it works if the children are already populated. In that case, when I click groups, nothing happens.
How to solve this?
So codes/web-link will be appreciated.
What I usually do is to add a "dummy child node" wherever there may be children that should be loaded in a lazy manner. This will make the parent have the plus sign, and then you can add code to the AfterExpand event where you do the following:
Check if there are are exactly one child, and if that child is the dummy node (you can use the Tag property to identify the dummy node)
If the dummy node is found, launch a search to get the children and add them to the parent node, finish it off by removing the dummy node.
I typically give the dummy node a text like "Loading data. Please wait..." or so, so that the user gets some info on what is going on.
Update
I put together a simple example:
public class TreeViewSample : Form
{
private TreeView _treeView;
public TreeViewSample()
{
this._treeView = new System.Windows.Forms.TreeView();
this._treeView.Location = new System.Drawing.Point(12, 12);
this._treeView.Size = new System.Drawing.Size(200, 400);
this._treeView.AfterExpand +=
new TreeViewEventHandler(TreeView_AfterExpand);
this.ClientSize = new System.Drawing.Size(224, 424);
this.Controls.Add(this._treeView);
this.Text = "TreeView Lazy Load Sample";
InitializeTreeView();
}
void TreeView_AfterExpand(object sender, TreeViewEventArgs e)
{
if (e.Node.Nodes.Count == 1 && e.Node.Nodes[0].Tag == "dummy")
{
// this node has not yet been populated, launch a thread
// to get the data
ThreadPool.QueueUserWorkItem(state =>
{
IEnumerable<SomeClass> childItems = GetData();
// load the data into the tree view (on the UI thread)
_treeView.BeginInvoke((Action)delegate
{
PopulateChildren(e.Node, childItems);
});
});
}
}
private void PopulateChildren(TreeNode parent, IEnumerable<SomeClass> childItems)
{
TreeNode child;
TreeNode dummy;
TreeNode originalDummyItem = parent.Nodes[0];
foreach (var item in childItems)
{
child = new TreeNode(item.Text);
dummy = new TreeNode("Loading. Please wait...");
dummy.Tag = "dummy";
child.Nodes.Add(dummy);
parent.Nodes.Add(child);
}
originalDummyItem.Remove();
}
private IEnumerable<SomeClass> GetData()
{
// simulate that this takes some time
Thread.Sleep(500);
return new List<SomeClass>
{
new SomeClass{Text = "One"},
new SomeClass{Text = "Two"},
new SomeClass{Text = "Three"}
};
}
private void InitializeTreeView()
{
TreeNode rootNode = new TreeNode("Root");
TreeNode dummyNode = new TreeNode("Loading. Please wait...");
dummyNode.Tag = "dummy";
rootNode.Nodes.Add(dummyNode);
_treeView.Nodes.Add(rootNode);
}
}
public class SomeClass
{
public string Text { get; set; }
}
It's standard behaviour for a tree to show a "+" in front of every folder/group, and the plus dissapears when clicked on if it's found to have no children, this saves the expensive "do you have children" check.
Alternatively you can provide this information if you have a cheap way of determining if a node has children. This question provides more information.

Categories

Resources