How to avoid winforms treeview icon changes when item selected - c#

I'm experimenting with a treeview in a little C#/Winforms application. I have programatically assigned an ImageList to the treeview, and all nodes show their icons just fine, but when I click a node, its icon changes (to the very first image in the ImageList). How can I get the icon to remain unchanged?
BTW: The "SelectedImageIndex" is set to "(none)", since I don't really know what to set it to, since the image-index is different for the nodes (i guess?).
UPDATE: Here is the code of the application (I'm using Visual Studio Express 2008):
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
treeView1.BeginUpdate();
treeView1.Nodes.Clear();
treeView1.Nodes.Add("root","Project", 0);
treeView1.Nodes[0].Nodes.Add("Foo", "Foo", 2);
treeView1.Nodes[0].Nodes[0].Nodes.Add("Fizz", "Fizz", 3);
treeView1.Nodes[0].Nodes[0].Nodes.Add("Buzz", "Buzz", 3);
treeView1.Nodes[0].Nodes.Add("Bar", "Bar", 1);
treeView1.Nodes[0].Nodes[1].Nodes.Add("Fizz", "Fizz", 2);
treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("Buzz", "Buzz", 3);
treeView1.EndUpdate();
treeView1.ImageList = imageList1;
}
}
}

Simply set the SelectedImageIndex for each node to the same value as ImageIndex. So, if you're creating your node programatically:
TreeNode node = new TreeNode("My Node");
node.ImageIndex = 1;
node.SelectedImageIndex = 1;
Or you can specify the whole lot in the constructor:
TreeNode node = new TreeNode("My Node", 1, 1);
You can do the same thing using the design time editor if you're adding nodes at design time. You just need to set the SelectedImageIndex at the node level and not at the TreeView level.

Hi You can also use the below code:
TreeNode Node = eventArgs.Node;
Node.SelectedImageKey = Node.ImageKey;

what can be done here is, we can utilize TreeView's HitTest method which gives the node information at a given point. Then with that info we can reset the Image to previous. Setting SelectedImageIndex to ImageIndex .Like so
var selectedNodeInfo = treeView.HitTest(treeView.PointToClient(Cursor.Position));
selectedNodeInfo.Node.SelectedImageIndex = selectedNodeInfo.Node.ImageIndex;

Related

Is there any way to find previous sibling in Coded UI

I have a Control which is first children of the Parent but nothing is unique in Parent and in the Control. I can find unique properties for Scond children so I need to find the previous Sibling of Second children
This is possible by using the SearchConfiguration property on the control.
What you do is you search for the label and next you instantiate a WinEdit control and pass it in the label search control. Next you set on the WinEdit instance the SearchConfiguration.Add(SearchConfiguration.NextSibling)
this will now search for the next sibling of the text label.
in a code example this looks like follows:
var app = ApplicationUnderTest.Launch(#"yourapplication.exe");
var mainWindow = new WinWindow(app);
mainWindow.WindowTitles.Add("Form1");
WinText textLabel = new WinText(mainWindow);
textLabel.SearchProperties.Add(WinControl.PropertyNames.Name, "Some Text Label");
WinEdit siblingEditControl = new WinEdit(textLabel);
siblingEditControl.SearchConfigurations.Add(SearchConfiguration.NextSibling);
siblingEditControl.Text = "setting the text";
There are no direct methods for getting siblings. One way of finding the siblings of a control is to find its parent and then find all the children of that parent. Next search through the children to find the current control and then take the previous one. The method might be based on the following. It uses the Name fields of the control for the comparison, this may be incorrect for the general case and I suggest other values be tried.
public UITestControl GetPreviousSibling(UITestControl uitc)
{
UITestControlCollection siblings = uitc.GetParent().GetChildren();
// Note that 'sibings[0]' has no predecessor
for (int ii=1; ii<siblings.Count)
{
if (uitc.Name == siblings[ii].Name)
{
return siblings[ii - 1];
}
}
return null;
}
The definition of "sibling" is not clear. This MSDN blog gives some details of siblings.

Panel Does not update TreeView

I have a TreeView that is displayed inside a panel. The data in the TreeView is based on data returned from the database. The first time, the data is correct. The second time, the TreeView is not refreshed, and the previous data is still showing in the tree. I checked the list that contain the data. The list returned the correct data. I've Google the issue, and could not resolved it with some of the answers that were posted. Here is a sample code of how the TreeView is being created and added to the Panel.
ReportGroups gr = new ReportGroups();
var Name = gr.GetReportName(groupID);
TreeView tr = new TreeView();
tr.BeginUpdate();
tr.Size = new Size(570, 600);
tr.Name = "Home";
tr.Nodes.Add("Reports Name");
tr.CheckBoxes = true;
if (Name.Count() > 0)
{
foreach (var item in Name)
{
if (item != null)
{
tr.Nodes[0].Nodes.Add(item.reportName);
}
}
}
tr.Nodes[0].ExpandAll();
tr.EndUpdate();
this.pDisplayReportName.Width = tr.Width * 2;
this.pDisplayReportName.Height = 300;
this.pDisplayReportName.Controls.Add(tr);
this.pDisplayReportName.Refresh();
What am I doing wrong?
try to add this.pDisplayReportName.Clear(); so data will not double up. :)
The easy option would be to use this.pDisplayReportName.Controls.Clear(); just after tr.EndUpdate();. But, this would cause an issue if you have other controls within the same Panel.
The best option would be to use this.pDisplayReportName.Controls.RemoveByKey("MyTree"); instead of this.pDisplayReportName.Controls.Clear();
And, another option would be to add a TreeView in design time (with name tr) rather than dynamically to the panel. Then, use tr.Nodes.Clear(); before tr.BeginUpdate(); and remove following two lines from your code.
TreeView tr = new TreeView();
.
.
.
this.pDisplayReportName.Controls.Add(tr);
Cheers

"Out of Memory" while populating TreeView

I am facing "Out of Memory" issue when I am populating TreeView hierarchy using XML. Our XML structure is very complex and it is not in fix format. There are multiple level of child nodes. I am using recursion to iterate XML and populate TreeView structure. I tried to call GC.Collect. to clear memory but still it is throwing same error.
I am using C# of .NET framework 3.5 for development.
I will appreciate if you can help me to find solution for this.
I'm providing the Code, Which I'm using for populating the treeview, below
private void addTreeNode(XmlNode xmlNode, TreeNode treeNode)
{
string attribute = "";
treeView1.ImageList = imageList1;
treeViewResponse.ImageList = imageList1;
XmlNode xNode;
TreeNode tNode;
XmlNodeList xNodeList;
foo.MoveToFollowing(XPathNodeType.Element);
namespaces1 = foo.GetNamespacesInScope(XmlNamespaceScope.All);
if (xmlNode.HasChildNodes)
{
treeNode.ImageIndex = 0;
treeNode.SelectedImageIndex = 0;
xNodeList = xmlNode.ChildNodes;
for (int x = 0; x <= xNodeList.Count - 1; x++)
{
xNode = xmlNode.ChildNodes[x];
treeNode.Nodes.Add(new TreeNode(xNode.Name));
tNode = treeNode.Nodes[x];
//treeNode.Nodes[x].ImageIndex = -1;
addTreeNode(xNode, tNode);
}
}
else
{
treeNode.ImageIndex = 1;
treeNode.NodeFont = new Font("Arial", 8, FontStyle.Bold);
treeNode.SelectedImageIndex = 1;
treeNode.Text = xmlNode.OuterXml.Trim();
}
}
As Raymond suggested, you should construct the font one time and reuse it. I have noticed that even if you do this, changing node fonts immediately causes a redraw of the control which can cause TreeView to construct internal fonts in addition to the one you provided it. I have seen cases where this can cause the font handle usage to go up very fast such that the garbage collector does not free them fast enough. I think this is a bug in TreeView that is not very repeatable but will happen sometimes. A way to protect yourself against Treeview using all your application's GDI handles is to wrap a set of node adds or font changes in TreeView.BeginUpdate() and TreeView.EndUpdate() calls.
m_treeView.BeginUpdate();
try
{
// TreeNode adds changes here
}
finally
{
m_treeView.EndUpdate();
}
This will result in only one redraw even though you added or changed multiple nodes.
Steve

Tree View not showing update

I have a TreeView in my Windows Form user interface.
I want to fill it up from a database, but it does not refresh ever, even though if I WriteLine() every node, it is in memory as I expect.
In order to make it more easy to understand, I wrote a little example program that only has one button that creates a TreeView and a TreeView called treeView1 to display its content.
If anyone can tell me where I have misunderstood the use of the TreeView, it would be a tremendous help.
private void button1_Click(object sender, EventArgs e)
{
// create a tree
TreeView t = new TreeView();
TreeNode[] child = new TreeNode [1];
child[0]=new TreeNode("myCat");
child[0].Name = "IndependantOne";
TreeNode categoryNode = new TreeNode("catIdTag", child);
categoryNode.Name = "Citizen Cat 5239002147";
t.Nodes.Add(categoryNode);
// some stuff under the first node
TreeNode[] mouseNode = new TreeNode[1];
mouseNode[0] = new TreeNode("myMouse");
mouseNode[0].Name = "SqueakyOne";
TreeNode[] childItem = new TreeNode[1];
childItem[0] = new TreeNode("mouseIdTag", mouseNode);
childItem[0].Name = "Citizen Mouse 54655654649";
TreeNode eltNode = new TreeNode("Cheese", childItem);
eltNode.Name = "Emmental";
t.Nodes["Citizen Cat 5239002147"].Nodes.Add(eltNode);
// fill in the winform treeview
if (t != null)
{
//treeView1.Visible = false;
treeView1.BeginUpdate();
treeView1.Nodes.Clear();
treeView1.TopNode = t.TopNode;
foreach (TreeNode n in t.Nodes)
{
treeView1.Nodes.Add(n);
System.Diagnostics.Debug.WriteLine("Category Node contains: " + treeView1.Nodes[n.Name].Name + " at " + treeView1.Nodes[n.Name].Level);
foreach (TreeNode no in treeView1.Nodes[n.Name].Nodes)
{
System.Diagnostics.Debug.WriteLine("Category Node Nodes contains: " + no.Name);
}
}
/*
This part I tried and it doesn't work either, still add it in the question if anyone knows if it's wiser?
this.treeView1 = t;
this.treeView1.Location = new System.Drawing.Point(233, 12);
this.treeView1.Name = "treeView1";
this.treeView1.Size = new System.Drawing.Size(351, 277);
this.treeView1.TabIndex = 11;
this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect);
*/
treeView1.EndUpdate();
this.treeView1.Update();
this.treeView1.Refresh();
treeView1.Show();
//this.Refresh();
}
}
I also tried setting the treeView1 with
treeView1 = t;
It was not a success...
change
treeView1.Nodes.Add(n);
with
treeView1.Nodes.Add((TreeNode)n.Clone());
You cannot host the same node in more than one TreeView control.
Alternatively, you can remove nodes from source TreeView before adding them to other TreeView:
while(t.Nodes.Count != 0)
{
var node = t.Nodes[0];
t.Nodes.RemoveAt(0);
treeView1.Nodes.Add(node);
}
And I hope that there is a real reason why you create and fill tree view in your method instead of directly filling an already existing one. If it is not an intended behavior, remove the if block completely and change TreeView t = new TreeView(); to var t = treeView1.
This behavior is expected because with this code you`re confusing node-to-treeview relationship nature of the native .NET treeview control. Instead when moving nodes between treeviews (t -> treeView1) you need to clone them as suggested. Without that moved node still linked with the old treeview (see node.Treeview property) and because original tree (t) is not visible/added to any parent (form), I guess node will be invisible as well.
Also, the way you`re working with data loading (through creating new treeview) is pretty bad pattern. Instead you need to download your data (async I guess) into a temp buffer and recreate the treeView1 at once when data will be available with BeginUpdate/EndUpdate calls.
PS. Replacing treeView1 variable with 't' won't work as well because you don't replace the treeview control instance in the parent form/panel Controls property with this code.

TreeView selected node problem

i wanted to create a custom treeview so i inherited the treeview class and created 'CustomTreeView' class
there i implemented multiselect concept..
for making the node as selected,
node.BackColor = SystemColors.Highlight;
node.ForeColor = SystemColors.HighlightText;
i used these lines...
but the problem is when i make the control as disabled(ie enabled=false),
the selected node goes invisible..
any other solution to make a node selected??? without this enabled problem?
EDIT: Here is the full function that is called when a node is selected:
private void ToggleNode(TreeNode node, bool bSelectNode)
{
if (bSelectNode)
{
m_SelectedNode = node;
if (!m_SelectedNodes.Contains(node))
m_SelectedNodes.Add(node);
node.BackColor = SystemColors.Highlight;
node.ForeColor = SystemColors.HighlightText;
}
else
{
m_SelectedNodes.Remove(node);
node.BackColor = this.BackColor;
node.ForeColor = this.ForeColor;
}
}
I suspect it's because Highlight and HighlightText are sufficiently close together that you get this effect with the dimming.
Try Red and Blue. Does it still disappear?

Categories