VisualDiagnostics.VisualTreeChanged event without attached debugger? - wpf

In WPF there is an event VisualDiagnostics.VisualTreeChanged that triggers every time a new element is added to the visual tree (anywhere). The problem is that this only works when a debugger is attached to the process. Is there any way of getting around this limitation? Any other similar event that works without a debugger? Can I fake an attached debugger?
My goal is to get a list of all elements of certain types (Button, TextBox, ComboBox etc) in a Window, including those generated from a template. I need this to set certain automation properties in runtime.
One possibility is to use the Window.LayoutUpdated event, but this triggers very often and most of the times without any new elements added. I would have to iterate through the entire visual tree on every layout update to find new elements and I don't think that will be very efficient. I would certainly prefer a more direct method.
But the VisualDiagnostics.VisualTreeChanged event is not ideal either since the element in the event-args does not yet contain any of it's children. A button would for instance not even have it's own text-content yet. If there were a third option where I could get hold of the entire element-fragment of all new elements as they are added that would be great.
(Have tried overriding OnVisualChildrenChanged as well but this does not catch new descendant elements, only children it seem)

Related

How to optimize TreeNode name change?

I have a TreeView which holds approximately 100,000 TreeNodes or even more, I have optimized everything related to loading or unloading them on deserialization process but now I'm stuck with an issue I can't overcome.
Its important to mention I decided not to use the LabelEdit default event given by the control since its pretty tricky to make it work as I wanted to, Its widely known that there are a lot of "problems" with this particular event which have pushed many devs to implement their own custom TreeViews.
In my case I am using a ContextMenu which has a Rename option, this brings a textbox right in front of the TreeNode and then I just simply change the TreeNode.Text property to whatever the user input was in the TextBox keydown event, once we trigger this event, the whole GUI freezes for a couple of seconds (4-5), I'm not doing any Depth search over the TreeNodeCollection or anything, I am directly accessing the TreeNode and modifying the property...
So, any thoughts on what could be wrong here? I already tried BeginUpdate / SuspendLayout / or even a custom solution found here How do I suspend painting for a control and its children? and nothing seems to help.
The first thing that comes to mind is that when the text is changed on the node, it must be redrawing the entire treeview.
In this situation, suspendlayout will not help, as the control isn't laying its contents.
I think beginupdate stops the drawing when nodes are being added to the list, but the text changed might bypass this.
Have you considered not using the keydown, and just updating the text once the user has dismissed the textbox? (i.e. done editing). Not ideal, but will limit the performance hit to once, instead of every key stroke?

Access WPF DataGrid after making element visible

Currently I am stuck with a problem that is simple on the first sight. Its about automated GUI testing.
I want to make a row/cell of a WPF DatGrid completely visible by scrolling using ScrollIntoView(row) and then accessing the row/cell directly after. Unfortunately scrolling in ScrollViewer seems to happen asynchronously. This means I need to wait for the scrolling to finish before accessing the row/cell. For this purpose I found the ScrollChanged event I can subscribe.
There is only one detail I can not solve: If the row/cell I want to access is already visible (and no scrolling is necessary) I do not get that event and the algorithm gets stuck. I was not able to find a reliable way to predict if a call to ScrollIntoView(row) actually scrolls.
Any idea how to solve this?
To make sure layout is updated call UIElement.UpdateLayout after you ScrollIntoView and before you want to use item. Quoting MSDN it
Ensures that all visual child elements of this element are properly updated for layout.

How to get an event when WinForms TreeView items gets cleared

I am using a standard TreeView in a WinForms application and everything works fine except for one issue:
Parts of the system need to change depending on the selected TreeNode, which works fine using the AfterSelect event.
However, sometimes the TreeView will get cleared completely resulting in an empty selection which does not trigger this event.
At the momemnt I am calling the event callback manually to fix this issue.
This is obviously dangerous, since I will forget to call this function somewhere. Is there a "correct" way to do this?
Thank You!
This is by design. The underlying native Windows controls only generate notifications for things you cannot figure out yourself. The ListBox control for example doesn't have any event that tells you an item got added or removed. Which is because there is no way for the user to add or remove items. Similarly, there's no way for the user to remove the nodes from a tree view.
These kinds of changes requires code that you write. Since it is your code, you cannot not know that these changes happened. If you want an event then you'll have to raise it yourself. Beware that this is harder than it looks, the TreeNodeCollection class doesn't reliably let you generate an event for programmatic changes to the node collection. It doesn't behave like an ObservableCollection. You are definitely better off by not needing this event.

Adding controls causes silverlight to hang

I have a very strange issue that I'm finding it extremely hard to debug, thus I once more turn to the SO community. :-)
First a bit on my setup (note! I'm new to silverlight, just learning by doing, so my entire premise might be wrong!):
I have some root nodes (forms) under which are some leaves (questions).
Now, I simply want to show / hide the questions depending on which form is currently selected - fairly easy.
I do the following:
A number of controls are added to a LayoutControl (I'm using the DeveloperExpress components)
When you select another form, the created controls are saved in a list on the previously selected form
When you select a form, the list of controls is iterated through, and each element is added to my layoutcontrol again
When I save the elements in the list on a Form I make sure to first .Remove() them from their parent to make sure there are no issues with that.
And, this works.
If I have 1 or controls.
If I have MORE than that, everything is added as usual, no exception is thrown - but Silverlight apparently does an infinite loop somehow? No matter if I run it in IE or Chrome, it just crashes the browser! (Or, I guess, the browser plugin).
I've tried pausing the debugger during this to see where the problem is, but it just stops in "external code".
I don't think a code sample will do much good, but here's the two methods that save and load the elements: (Note: AddControl is a method I've defined - it wraps the element in another control to provide a bit of functionality. Likewise .MyChildren removes the control from the wrapper using .Remove() and returns it)
private void LoadElementsFromCurrentForm()
{
foreach (var child in _currentForm.Elements)
{
layoutControl1.AddControl(child);
}
}
private void SetElementsOnCurrentForm()
{
_currentForm.Elements.Clear();
foreach (var child in layoutControl1.MyChildren)
{
_currentForm.Elements.Add(child);
}
}
How do I even go about debugging this!?
I don't know if it matters, but all these controls have a unique name as well.
Regards
Søren
To take full advantage of Silverlight you should try to use XAML to do the markup of design.
If you want to make a list of questions use e Listbox or ItemsControl.
Then you can style each item in the list to "look right".
If you bind the listbox to ObservableCollection you just add or remove in the list and the gui will be updated according to whats in your list.
Take a look at MVVM which works really good with Silverlight.

WPF Routed Events Across Element Tree Branches

I am wondering what the correct mechanism to enable communication between controls in WPF is. My goal is to not use conventional events and have to manually wire them up. The default behavior of routed commands (tunneling, bubbling) seems to be along the right lines but I guess I'm missing something.
Routed events are a new infrastructure provided by WPF which allows events to tunnel down the visual tree to the target element, or bubble up to the root element. When an event is raised, it “travels” up or down the visual tree invoking handlers for that event on any element subscribed to that event it encounters en route. Note that this tree traversal does not cover the entire visual tree, only the ancestral element
That is from this WPF Article
Using the image in the article, I want "Immediate Element #1" to initiate (raise) an event and then have "Immediate Element #2" handle that event. I'd like to achieve this without having to put any code in the "Root Element".
Basically fire an event (save, status updated, selection changed, etc..) from any where in my app, then have it be handled somewhere else with out the 2 parties knowing anything about each other. Is this possible?
I dont believe data bainding is the answer. I'd like to use Routed Events / Commands as they were designed just across the entire tree, not just within the source control's branch. Maybe it can't be done using routed events / commands, and data binding is the answer. I just dont know...
Any ideas?
The best mechanism is to refactor and separate the data view from the data model.
Create a data model that provides DependencyProperty properties (rather than standard C# properties) for each data point, but does not provide a UI. The values in the data model can affect each other when modified.
You can then bind each WPF element to the appropriate DependencyProperty from the data model. Modify the value in one element and all other elements are updated to reflect any data model changes in the bound properties.
If you want to transfer data between elements, Binding is the way to go. There are many tutorials and books about this on the net.
If you want to effect Style changes, then you can use DataTriggers, which also use Bindings.
There is no way to send events in the traditional sense between unrelated controls without wiring it up in the common root.

Resources