I have a problem I've ran into and I'm not sure if it is possible to prevent it. I supose it is designed like this by default.
I have coded a treeview list to be filled by a XML and each of these node, when selected, are filling some textbox. Depending on their type, it will trigger a different function.
The problem is that when I select a child, it seems to trigger "IsSelecting" for all parents treeviewitem all the way to the top which in return trigger the associated function as well and I don't want that.
Any idea how to prevent this "Sort of reverse inheritance" for IsSelected?
Example (check with code below): selecting a "node" will trigger "Node_Selected", "Dialog_Selected", "Actor_Selected".
Thanks for your help.
Best regards,
Just for context:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
XmlDocument document = new XmlDocument();
document.Load("XML/ActorsDialogs.xml");
XmlNodeList actors = document.SelectNodes("/dialogs/actor");
foreach (XmlNode actor in actors)
{
TreeViewItem newActor = new TreeViewItem();
newActor.Header = actor.SelectSingleNode("actorname").InnerText;
newActor.Selected += new RoutedEventHandler(Actor_Selected);
XmlNodeList dialogs = actor.SelectNodes("dialog");
foreach (XmlNode dialog in dialogs)
{
TreeViewItem newdialog = new TreeViewItem();
newdialog.Header = "Dialog:" + dialog.SelectSingleNode("dialogID").InnerText;
newdialog.Selected += new RoutedEventHandler(Dialog_Selected);
BuildNodes(newdialog, dialog);
newActor.Items.Add(newdialog);
}
ActorsList.Items.Add(newActor);
}
}
private void BuildNodes(TreeViewItem treeNode, XmlNode parentElement)
{
foreach (XmlNode child in parentElement.ChildNodes)
{
if (child.Name == "node" || child.Name == "reply")
{
XmlElement childElement = child as XmlElement;
TreeViewItem childTreeNode = new TreeViewItem();
string ID = child.SelectSingleNode(child.Name + "ID").InnerText;
childTreeNode.Header = childElement.Name + ":" + ID;
switch (child.Name)
{
case "node":
childTreeNode.Selected += new RoutedEventHandler(Node_Selected);
break;
case "reply":
childTreeNode.Selected += new RoutedEventHandler(Reply_Selected);
break;
default:
break;
}
treeNode.Items.Add(childTreeNode);
BuildNodes(childTreeNode, childElement);
}
}
}
private void Actor_Selected(object sender, RoutedEventArgs e){}
private void Dialog_Selected(object sender, RoutedEventArgs e){}
private void Node_Selected(object sender, RoutedEventArgs e){}
private void Reply_Selected(object sender, RoutedEventArgs e){}
In the event handler you can set e.Handled = true. That will prevent the event from bubbling up the tree.
private void Node_Selected(object sender, RoutedEventArgs e)
{
e.Handled = true; //this will prevent the event from bubbling up to parents;
//Do the rest of the code here.
}
See https://msdn.microsoft.com/en-us/library/ms742806%28v=vs.110%29.aspx for more information on RoutedEvents. These include bubbling events which go up the tree and tunneling events which go down the tree.
Related
In a Winforms application, I have this code:
private void BtnNuevoGrupo_Click(object sender, EventArgs e)
{
TreeNode newNode = TreDevices.Nodes[0].Nodes.Add("Nuevo grupo de validaciĆ³n");
TreDevices.Nodes[0].Expand();
TreDevices.SelectedNode = newNode;
newNode.Tag = "IN:0";
newNode.BeginEdit();
}
With that code, I am adding a tree node and starting edit immediately. Then, I have this code:
private async void TreDevices_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
{
e.Node.ContextMenuStrip = new ContextMenuStrip();
var itemEntrada = e.Node.ContextMenuStrip.Items.Add("Entrada");
itemEntrada.Click += InOutItem_Click;
}
Finally, I have this code to do some action when the context menu item is clicked:
private async void InOutItem_Click(object? sender, EventArgs e)
{
if (sender is not null)
{
var item = (ToolStripMenuItem)sender;
ContextMenuStrip menu = (ContextMenuStrip)item.Owner;
// HERE I NEED TO GET A REFERENCE TO THE TreeNode
}
}
In InOutItem_Click I need to get a reference to the TreeNode that owns the menu. How can I do it?
I can only get a reference to the tree control by using item.Owner.SourceControl.
Have you considered just using the Tag property of itemEntrada?
private void TreDevices_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
{
e.Node.ContextMenuStrip = new ContextMenuStrip();
var itemEntrada = new ToolStripMenuItem
{
Text = "Entrada",
Tag = e.Node,
};
e.Node.ContextMenuStrip.Items.Add(itemEntrada);
itemEntrada.Click += InOutItem_Click;
}
private void InOutItem_Click(object sender, EventArgs e)
{
if ((sender is ToolStripMenuItem tsmi) && (tsmi.Tag is TreeNode node))
{
var item = (ToolStripMenuItem)sender;
ContextMenuStrip menu = (ContextMenuStrip)item.Owner;
MessageBox.Show($"Clicked {node.Text}");
}
}
I'm really new to coding
I have a treeview that refreshes with a timer.
How can i make sure i keep my selected node highlighted every time it refreshes
Appreciate any help
Thanks
Here is the code that I have:
private void PopulateTree(ListObjectsResponse buckets)
{
treeView1.Nodes.Clear();
List<TreeItem> items = new List<TreeItem>();
foreach (S3Object obj in buckets.S3Objects)
{
treeView1.Nodes.Add(new TreeNode(obj.Key));
}
}
private void button4_Click_1(object sender, EventArgs e)
{
timer1.Enabled = true;
existingBucketName = label3.Text + "-DP";
AmazonS3Client client = new AmazonS3Client();
ListObjectsRequest listRequest = new ListObjectsRequest
{
BucketName = existingBucketName,
};
try
{
ListObjectsResponse listResponse;
listResponse = client.ListObjects(listRequest);
PopulateTree(listResponse);
}
catch
{
timer1.Enabled = false;
MessageBox.Show("There is no folder for this user");
}
}
Assuming that o.Key is a string, and that each string is unique and occurs at most once in buckets.S3Objects, try saving the selected value before repopulating the TreeView, then select it again afterwards.
private void PopulateTree(ListObjectsResponse buckets)
{
// Since you're about to clear out all current TreeNode instances, storing a
// reference to SelectedNode is not enough. You're setting o.Key as the Text
// for each TreeNode, so save the selected node's Text value.
var selectedText
= treeView1.SelectedNode == null ? "" : treeView1.SelectedNode.Text;
// Repopulate your TreeView with new TreeNodes
treeView1.Nodes.Clear();
treeView1.Nodes.AddRange(buckets.S3Objects.Select(o => new TreeNode(o.Key)).ToArray())
// Look for the TreeNode with the same Text that you had selected before.
// If it's not found, then SelectedNode will be set to null
treeView1.SelectedNode =
= treeView1.Nodes.Cast<TreeNode>()
.SingleOrDefault(n => n.Text == selectedText);
}
Several of the above methods, such as Select, Cast, and SingleOrDefault, are part of LINQ.
Assuming this is ASP.NET (not ASP.NET MVC) that you're talking about, you would do this in the Page_Load() event handler. Be sure to check whether IsPostBack == true
For example,
private void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// set selected node here
}
}
If you are using ASP.NET MVC then just store the property in the ViewBag.
I have the following code which checks each radio button (Temp30, Temp40 and Temp60) and does the necessary things such as turning the wash temperature light on etc...
I want to create an event which handles all 3 radio buttons. I thought it could possibly have something to do with the groupbox they are in? (it is called TempGroupBox)
Any help would be much appreciated!
private void Temp30_CheckedChanged(object sender, EventArgs e)
{
if (Temp30.Checked)
{
MainDisplayLabel.Text = (" SELECT SPIN SPEED");
WashTempLight.Visible = true;
WashTempLight.Image = Properties.Resources._30degrees;
SpeedGroupBox.Enabled = true;
}
}
private void Temp40_CheckedChanged(object sender, EventArgs e)
{
if (Temp40.Checked)
{
MainDisplayLabel.Text = (" SELECT SPIN SPEED");
WashTempLight.Visible = true;
WashTempLight.Image = Properties.Resources._40degrees;
SpeedGroupBox.Enabled = true;
}
}
private void Temp60_CheckedChanged(object sender, EventArgs e)
{
if (Temp60.Checked)
{
MainDisplayLabel.Text = (" SELECT SPIN SPEED");
WashTempLight.Visible = true;
WashTempLight.Image = Properties.Resources._60degrees;
SpeedGroupBox.Enabled = true;
}
}
You can bind all radioButton's event to the same handler and use sender parameter to get the control that the action is for.
private void Temps_CheckedChanged(object sender, EventArgs e)
{
string checkedName = ((RadioButton)sender).Name;
if(checkedName == "Temp40")
{
...
}
else if(checkedName == "Temp60")
{
...
}
}
You can add event handler for all RadioBUttons's like that after InitializeComponent():
var radioButtons =this.Controls.OfType<RadioButton>();
foreach (RadioButton item in radioButtons)
{
item.CheckedChanged += Temps_CheckedChanged;
}
On Selecting a particular I want to highlight the treepath with nodes as bold one.
protected void Trv_SelectedNodeChanged(object sender, EventArgs e)
{
HighlightPath(Trv.SelectedNode);
}
private void HighlightPath(TreeNode node)
{
node.SelectAction = TreeNodeSelectAction.None;
node.Text = "<div style=font-weight:bold>" + node.Text + "</div>";
if (node.Parent != null)
HighlightPath(node.Parent);
}
But next time if I am slelecting another node its should mark previous nodes unbold and new path as bolded one. Please help on this.
You can solve this by stroring all highlighted nodes in a List<TreeNode> and before highlighting a new path, you un-highligt the items in the list.
// New list of currently highlighted nodes
protected List<TreeNode> highlightedNodes = new List<TreeNode>();
protected void Trv_SelectedNodeChanged(object sender, EventArgs e)
{
// Call the method to un-highligt first
UnHighlightNodes();
HighlightPath(Trv.SelectedNode);
}
private void UnHighlightNodes()
{
foreach(var node in highlightedNodes)
{
// TODO: code to un-highlight nodes
}
// Clear List of highlighted nodes
highlightedNodes.Clear();
}
private void HighlightPath(TreeNode node)
{
node.SelectAction = TreeNodeSelectAction.None;
node.Text = "<div style=font-weight:bold>" + node.Text + "</div>";
if (node.Parent != null)
HighlightPath(node.Parent);
// Store the node in the list of highlighted nodes
highlightedNodes.Add(node);
}
This could be optimized further to prevent un-highlighting and then immediatley highlighting again. Like this:
// New list of currently highlighted nodes
protected List<TreeNode> HighlightedNodes = new List<TreeNode>();
protected void Trv_SelectedNodeChanged(object sender, EventArgs e)
{
var nodesToHighlight = FindPathToRoot(Trv.SelectedNode).ToList();
// Un-highlight nodes (except those which should stay highlighted)
UnHighlightNodes(HighlightedNodes.Except(nodesToHighlight));
// Highlight nodes (except nodes already highlighted)
HighlightNodes(nodesToHighlight.Except(HighlightedNodes));
// Save the new list of highlighted nodes;
HighlightedNodes = nodesToHighlight;
}
private static IEnumerable<TreeNode> FindPathToRoot(TreeNode node)
{
do
{
yield return node;
node = node.Parent;
} while (node != null);
}
private void UnHighlightNodes(IEnumerable<TreeNode> nodes)
{
foreach (var node in nodes)
{
// TODO: code to un-highlight nodes
}
}
private void HighlightNodes(IEnumerable<TreeNode> nodes)
{
foreach (var node in nodes)
{
node.SelectAction = TreeNodeSelectAction.None;
node.Text = "<div style=font-weight:bold>" + node.Text + "</div>";
}
}
I think you need to bold selected node and its Parent node in a treeview asp.net page.
If its so you don't need to make it complex. Please try to put this in your page load event as shown .
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
foreach (TreeNode ParentNodes in TreeView1.Nodes)
{
ParentNodes.Text = ParentNodes.Text.Replace("<b>", "").Replace("</b>", "");
foreach (TreeNode ChildNodes in ParentNodes.ChildNodes)
{
ChildNodes.Text = ChildNodes.Text.Replace("<b>", "").Replace("</b>", "");
}
}
TreeNode node = TreeView1.SelectedNode;
node.Text = Server.HtmlDecode("<b>" + node.Text + "</b>");
node.Parent.Text = Server.HtmlDecode("<b>" + node.Parent.Text + "</b>");
}
}
Here TreeView1 is my treeview . You don't need to do anything in SelectedNodeChanged event for this.
I have a Treeview with checkboxes when I click the parent node checkbox that child node will also be checked
I want to get the checked child node value
In the below code I got all the checked values even parent node value
But I don't want that parent node.
protected void btnAdd_Click(object sender, EventArgs e)
{
if (TreeView1.CheckedNodes.Count > 0)
{
foreach (TreeNode node in TreeView1.CheckedNodes)
{
string checkedValue = node.Text.ToString();
activityData = new ActivityData { ActivityName = checkedValue };
listActivity.Add(activityData);
Session["listActivity"] = listActivity;
}
}
}
In the above image I don't want to get HR Activity(Parent node)
Any ideas? Thanks in advance
Use the following code. The main parent node does not have a parent.
You only need to set the session variable at the end of the foreach
Keep in mind that accesing or assigning session variables means that a deserialization/serialization of the object is happening
Also I dont know if maybe you need to clear or initialize the listActivity before the foreach. You can do this either with
listActivity = new List<ActivityData>() ;
or
listActivity.Clear();
Here is the code
protected void btnAdd_Click(object sender, EventArgs e)
{
if (TreeView1.CheckedNodes.Count > 0)
{
foreach (TreeNode node in TreeView1.CheckedNodes)
{
//The main parent node does not have a parent
if(node.Parent != null)
{
string checkedValue = node.Text.ToString();
activityData = new ActivityData { ActivityName = checkedValue };
listActivity.Add(activityData);
}
}
//stablish the session variable only when the foreach has finished
Session["listActivity"] = listActivity;
}
}
There's a property of a treeview node called Level, so you could skip nodes with a level of 0, course that will break down if you nest a level deeper.
If you know which parent node it is, then iterate through it's children and test for checked.
protected void btnAdd_Click(object sender, EventArgs e)
{
if (TreeView1.CheckedNodes.Count > 0)
{
foreach (TreeNode node in TreeView1.CheckedNodes)
{
if (node.Level > 0)
{
string checkedValue = node.Text.ToString();
activityData = new ActivityData { ActivityName = checkedValue };
listActivity.Add(activityData);
Session["listActivity"] = listActivity;
}
}
}
}