Treeview AfterLabelEdit Keeps Firing? - c#

I have a tree view and it's populated with tow parent nodes, and sub nodes for each parent node. I have added like a template node "Add New" in order to do database insertion, so i add the "OnNodeMouseDoubleClick" event to begin node edit, afer that i call the "AfterlabelEdit" event and do the insertion which is successfull with no problems, but the thing is that it this event keeps firing for the numbers of the sub nodes included on the parent. Is there anything wrong or that how it does work and if so is there any solution ?

if(e.Node.IsEditing == true)
{
//your code here
e.CancelEdit = true;
}

Related

Treeview re-select node by code after use

When selecting a treenode in my WinForm treeview, it gets highlighted with the blue background to indicate it is selected.
Once the user hits a button, the selected node gets used in some code. In this example, when the button is pushed, the node moves up an instance.
But once the code has executed, the selection is lost. Now the user have to re-select the node by hand and hit the button again to move it up again.
So what i would want, is that the node gets re-selected after the code has executed.
i tried doing that with this code, but that does not seem to have any effect on the selection:
TreeNode t = treeView1.SelectedNode;
//do something
Extensions.MoveUp(treeView1.SelectedNode);
//re-select ?
treeView1.SelectedNode = t;
Is there some other way to set the selection again by code after executing my method ?
EDIT (SOLVED - Not deleting post in case sombody in the future is looking for the same thing):
All i had to do was cast the focus as the final step:
treeView1.Focus(); did the trick

Actually deselect all nodes in TreeView (.NET)

I'm trying to actually deselect all nodes in my TreeView. By "actually", I mean that TreeView1.SelectedNode = null; will actually deselect the node in the tree.
Right now, visually speaking, the node is deselected. However, when I try to add a new node, the treeview will automatically select the first node in the tree (at the top) and create a subnode when ideally I want to create a parent node. I can't just deselect the selected node before adding either, because the user might want to add a child node. The behaviour I'd like is for the parent/child node adding to be based on what is selected in the treeview. If nothing is selected, add a parent, if something is selected, add a child in that selected node.
I construct a TreeNode object called node in a function with images and text and all that then I have the following:
if (tvContent.SelectedNode == null)
tvContent.Nodes.Add(node);
else
{
tvContent.SelectedNode.Nodes.Add(node);
tvContent.SelectedNode.Expand();
}
I have a "Deselect All" button that is supposed to make the above code work. The code for that button is simply:
tvContent.SelectedNode = null;
Pardon my tagging both C# and VB.NET. I'm good with both so if someone can help me out in either language that'd be terrific!
Thanks
EDIT:
Interesting. It seems that while testing if the selected node is null, .NET will automatically set the selected node to the first node in the tree. The following code shows the "trigger" message box, but immediately selects the first node in the tree after the if statement is complete.
private void btnDeselectAll_Click(object sender, EventArgs e)
{
tvContent.SelectedNode = null;
if (tvContent.SelectedNode == null) MessageBox.Show("trigger");
}
EDIT2: The issue lies in using an InputBox for the title input of the node. For whatever reason, that changes the selected node of the treeview. I tried this in a stock project and managed to replicate the issue. I guess there's no fixing this :S
So it turns out that getting "true" deselection isn't possible. As soon as the treeview loses focus then gains focus again (e.g. via an inputbox window popping up), the selected node will no longer be null.
My work around was to introduce a panel that becomes visible with some input options so that node title input is done on the main form instead of on another form. I don't like this fix but it's all that can be done.
This worked for me
Private LastSelectetNode As TreeNode
Protected Overrides Sub OnBeforeSelect(e As TreeViewCancelEventArgs)
e.Cancel = LastSelectetNode Is Nothing
MyBase.OnBeforeSelect(e)
End Sub
Protected Overrides Sub OnMouseUp(e As MouseEventArgs)
Dim nd = MyBase.HitTest(e.Location).Node
If LastSelectetNode Is nd Then
SelectedNode = Nothing
LastSelectetNode = Nothing
Else
LastSelectetNode = nd
End If
MyBase.OnMouseUp(e)
End Sub
I tried to reproduce your scenario but failed. After setting SelectedNode to null, it remained null for me when trying to read it back. A few things I want to check on:
Are you sure you're actually deselecting the node? If you have the "HideSelection" property of the TreeView set to True (default), the selection disappears anytime the TreeView loses focus (like when you click your deselect all button - making it look like it's working). Make sure this isn't the case by setting HideSelection to False.
Are you sure you're not triggering an event handler (like SelectedNodeChanged) when you set the SelectedNode to null?

Change TreeListNode Index (Position) in DevExpree TreeList Control

I'm using DevExpree XtraTreeList Control, I want to randomly Set one of the first levels nodes to be the first node in the Tree, nothing helpful shown in the TreeList Control's Methods nor in the TreeListNode Methods,
Please Advice.
Edit: My Code
private void btnSetMaster_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
{
//Load reprot
if (treeLstRprtDS.FocusedNode != null)
{
treeLstRprtDS.SetNodeIndex(treeLstRprtDS.FocusedNode,0);
//Get selected underlying object
ReportDataSource rprtDataSourceSelected =
(ReportDataSource)treeLstRprtDS.GetDataRecordByNode(treeLstRprtDS.FocusedNode);
theReport.SetReportDataSourceAsMaster(rprtDataSourceSelected);
}
}
Edit:
Note: working on bound mode
Solution:
I implemented the CompareNodeValues Event for the XtrTreeList Control
Read here...
and then forced the tree to do sorting using Column.SortIndex Read here...
Do you wish to scroll the TreeList so that a certain node to be the top one? If so, use the TreeList's TopVisibleNodeIndex property. If you need a certain node to be the first one, you should sort the TreeList within its CompareNodeValues event handler.
It sounds like you're looking for the SetNodeIndex method.

Treeview does not refresh to show childnode moved from one parent node to another

I am using the Windows Forms TreeView class which contains a set of TreeNodes. The TreeNodes can have child nodes.
I have a root node with 2 sub nodes (Node1 and Node2)
Node1 has 2 subnodes (child1 and child2)
I have a function that will allow a user to select any node and move it to another node:
TreeNode SelectNode = this.TreeView1.SelectedNode;
TreeNode DestNode = SelectedNewNode(); //function to select a new node
SelectedNode.Remove();
DestNode.Nodes.Add(SelectedNode);
this.TreeView1.Refresh();
When this executes, the current selected node (child2) is removed from its current parent
(Node1) and added to Node2.
However, the Refresh() method of the TreeView control does not show that child2 is under Node2. If I debug it and look at the Nodes collection in the TreeView i do see that child2 is under Node2.
Can anyone tell me why the Refresh() method does not redraw the new parent to child mapping?
Is there a way to tell the TreeView to redraw with the new mappings?
I don't know if this is just a typo or not, but in the first line you refer to SelectNode and then you later add something called SelectedNode. These might be referring to different variables/properties.
Otherwise, there is either a problem with your SelectedNewNode function, or this code is being executed in some long-running synchronous operation and no repaints are happening at all. You don't need the Refresh method at all; when you invoke the Remove() method on a TreeNode, the display will be updated, and when you Add it to another parent, it will be updated again. Remove the Refresh call.
If you are indeed trying to update during a long-running operation, then you need to invoke Invalidate followed by Update. However, if this isn't in a loop or blocking call somewhere, that's going to be pointless.
There's one other possibility, which is that you've invoked the TreeView.BeginUpdate method and forgotten to invoke TreeView.EndUpdate, which would prevent any updates from being displayed.
Just to test this out, I tested this on a new Windows Form with a TreeView added two roots (Node0 and Node1) and one child to each (Node2 and Node3). The following code successfully updates the display of the TreeView:
TreeNode nodeToMove = treeView1.Nodes.Find("Node3", true).First();
TreeNode newParent = treeView1.Nodes.Find("Node0", false).First();
nodeToMove.Remove();
newParent.Nodes.Add(nodeToMove);
If none of the above suggestions solve your problem, then start from this working example and look at the difference between the working example and your current code.

Can I insert nodes into a TreeView during AfterLabelEdit without beginning to edit them?

I have a subclass of System.Windows.Forms.TreeView that's manually "bound" to a set of hierarchical data. I want the user to be able to edit the labels of the tree, and have the changes reflected back to the data. So I set LabelEdit to true and overrode OnAfterLabelEdit to the tune of:
protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e)
{
base.OnAfterLabelEdit(e);
TreeNode node = e.Node;
if (PassesSomeValidation(e.Label))
{
MyDataNode dataNode = node.Tag as MyDataNode;
dataNode.SomeBoundValue = e.Label;
int oldIndex = node.Index;
int newIndex = RepositionChangedDataNode(dataNode);
TreeNode parent = node.Parent;
parent.Nodes.RemoveAt(oldIndex);
parent.Nodes.Insert(newIndex, node);
}
else
{
e.CancelEdit = true;
}
}
RepositionChangedDataNode() re-sorts the data and returns the index into which the change node moved after sorting. I was hoping I could simply move the edited node to reflect this move.
The problem is that this causes the node to stay in edit mode! I've tried calling EndEdit(), cloning the node before inserting it, setting LabelEdit to false and back to true, wrapping the change in BeginUpdate()/EndUpdate(), and various combinations of these ideas, but none of them have any effect.
The culprit seems to be the insertion. Even if I attempt to insert a totally new node, it will go into edit mode immediately.
So, is there any way to make TreeView not behave this way? And if not, is there a good workaround?
Some ideas I've considered:
Set a custom TreeViewNodeSorter. Would prefer not to have to sort my data twice, though.
Set a flag and delay the remove-insert step until some point after AfterLabelEdit. It works to do it during WndProc, but this feels like a big kludge that is likely to fail somehow.
Use BeginInvoke() to push the remove-insert step back onto the message queue like so:
BeginInvoke(new MethodInvoker(delegate(
{
parent.Nodes.RemoveAt(oldIndex);
parent.Nodes.Insert(newIndex, node);
}));
This works and seems cleaner to me than #2, but I know this is probably not how BeginInvoke() was intended to be used, and that it may have repercussions that my very limited knowledge of the message pump cannot predict.
If you set LabelEdit for the TreeView to false, newly added nodes will not be in edit mode.
You just have to handle the case where the user wants to edit a label: Create a handler for the MouseClick event of the TreeView, where you get the clicked node by location. Set LabelEdit to true and call BeginEdit(). At the end of your handler for the AfterLabelEdit event (and after calling EndEdit(...) at an appropriate point), set LabelEdit to false again.
This works for me, whereas the solution with BeginInvoke only changed which node was in edit mode at the end.
try create a global variable, let's say:
private bool _allowEdit;
initialize it to true,
in your OnAfterLabelEdit method set it to false after your changes:
... int oldIndex = node.Index;
int newIndex = RepositionChangedDataNode(dataNode);
TreeNode parent = node.Parent;
parent.Nodes.RemoveAt(oldIndex);
parent.Nodes.Insert(newIndex, node);
**_allowEdit = false;**
}
else ...
then capture the OnBeforeLabelEdit event like this:
protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e)
{
base.OnBeforeLabelEdit(e);
e.CancelEdit = !_allowEdit;
_allowEdit = true;
}
I noticed that just after 'AfterLabelEdit' is fired, 'BeforeLabelEdit' is refired. That's why you have to stop it right there.
If you're using databinding, shouldn't the update to the data source (SomeBoundValue) trigger a refresh of the nodes? Maybe you can force the currency manager to repopulate the tree view.... If you're worried about performance you could use one of the sorting algorithms that works well with data that's almost already sorted (e.g., NOT quicksort - merge or heapsort come to mind)
Or you could dispense with data binding entirely and manually handle the repositioning since you're already half way there with RepositionChangedDataNode()....
You could try to unhook your OnEdit handler before adding the new node and re-hooking it after. I've seen that behavior before and that's how I handled it.

Categories

Resources