I have a TreeView with lots of items, obviously arranged in a tree structure. I am trying to print the parent node in bold and all its children in normal font. However, when I do:
TreeViewItem item = GetParentNode(...);
item.FontWeight = FontWeights.Bold;
this not only changes the parent's style to bold, but also all its children's. I have been looking for properties to disable this recursive update in the TreeView class, but I can't find any. How do I avoid this behaviour?
When you set the font properties it applies it to all children. You could create a new header template and apply it only to the nodes that are parents.
An alternative that has worked in my testing is setting the foreground color:
public MainWindow()
{
InitializeComponent();
StyleParents(MyTreeView.Items);
}
private void StyleParents(ItemCollection items)
{
foreach (var i in items)
{
TreeViewItem tvi = i as TreeViewItem;
if (tvi != null)
{
if (tvi.HasItems)
{
tvi.Foreground = Brushes.Magenta;
StyleParents(tvi.Items);
}
}
}
}
I found that in the WPF TreeView, properties are transferred onto their children if they haven't already been set. The easiest way to avoid this problem (programatically, at least) is to set the font of a child node to the default font as soon as it is created. E.g.
TreeViewItem item = new TreeViewItem ();
item.FontWeight = FontWeights.Normal;
// ...add item to tree
If you now set the FontWeight of a parent node to bold, the children will not change.
Related
Is there a way to evaluate the actual position of a TreeViewItem on a Canvas if its Parent TreeViewItem is collapsed (meaning <ParentTreeViewItem>.IsExpanded = false;)? When debugging neither the Visibility nor the Position information of the collapsed item in the parent´s ItemsHost seems to be updated.
Appreciating any hint!
Cheers, Alex
Found a workaround for this problem:
Basically whenever a TreeViewItem fires an OnCollapsed or OnExpanded event I force all other TreeViewItems to determine their own position based on the IsExpanded property of their ancestors up to the tree root.
If any of the ancestors is collapsed (i. e. IsExpanded == false) I apply its position to the current TreeViewItems position.
If none of the ancestors is collapsed, I apply its own position (whereas position is a custom Point property of the TreeViewItem).
Code sample:
private Point DeterminePosition()
{
Point point = this.position;
if (ParentTreeViewItem != null)
{
MyTreeViewItem parent = null, lastCollapsed = null;
parent = ParentTreeViewItem;
while (parent != null)
{
if (parent.IsExpanded == false)
{
lastCollapsed = parent;
}
parent = parent.ParentTreeViewItem;
}
if (lastCollapsed != null)
{
point = new Point(position.X, lastCollapsed.Position.Y);
}
}
return point;
}
I have a UserControl contained in a class When some conditions are met I initialize the UserControl and I add it in a Grid, setting row and column property depending on the position of the class in a list. When I change that position, I need to update the position of the element on the Grid, but since not every class has its UserControl initialised and added, I need to check when I order the elements in the Grid.
To check if the UserControl is initialised I check if it is null
classElement.userControl == null
How do I check if the UserControl has been added to the Grid?
Perhaps the easiest way to achieve your requirements would be for you to simply iterate through the children of the Grid using the Children property, checking each one in turn. You could do something like this:
<Grid Name="YourGrid">
...
</Grid>
...
foreach (UIElement uiElement in YourGrid.Children)
{
if (uiElement.GetType() == typeof(UserControl))
{
if (uiElement != null)
{
// Do something with your control here
}
}
}
UPDATE >>>
I don't understand your comment... you said I need a way to know if the usercontrol is in the grid or not... that is exactly what I have provided you with. If you are adding the UserControl to the Grid, then you must have a reference to the Grid. If you have a reference to the Grid, then you can iterate the controls that have been added to that Grid just as I have shown you. If you are adding the UserControl from the UserControl code behind, then you can do this:
foreach (UIElement uiElement in YourGrid.Children)
{
if (uiElement.GetType() == typeof(UserControl))
{
if (uiElement != null)
{
if (uiElement == this)
{
// this UserControl is in the Grid
}
}
}
}
If this does not solve you problem, then please take the time to provide a decent description of your problem that would enable me to suggest a fix for it. From what I understand presently, this is your fix.
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.
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?
I need to change the group box text to a specific color without changing the color of what is inside the group box.
The following code sets the ForeColor of the GroupBox to pink but this settings cascades to all the child controls as well:
groupbox.ForeColor = Color.Pink
How do I change the ForeColor of a GroupBox without having that color applied to every child control as well?
You could iterate through all the controls in the GroupBox and set their respective ForeColor properties:
groupBox1.ForeColor = Color.Pink;
foreach (Control ctl in groupBox1.Controls) {
ctl.ForeColor = SystemColors.ControlText;
}
form_load()
{
...
foreach (Control ctl in groupbox.Controls)
{
// load color value from parent and explicitly set it to control level
ctl.ForeColor = ctl.ForeColor;
}
...
}
some_click()
{
groupbox.ForeColor = Color.Pink;
}
someother_click()
{
groupbox.ForeColor = Color.Green;
}
Color is not set for childcontrol until it done explicitly, and when childcontrol color requested it taken from the parent. Changing parent's color will refresh all it's content and childcontrol will take color from the parent.
If you set (explicitly) child color then child will not "asking" parent.
Child color can be set in designer too, but if color is the same as parent's color, designer will reduce this setting. Code in load event force child to have own color.