WPF UI Automation - AutomationElement.FindFirst fails when there are lots of elements - wpf

We've got some automated UI tests for our WPF app (.NET 4); these test use the UI Automation API's.
We call AutomationElement.FindFirst to find a target element, and then interact with it.
Example (pseudocode):
var nameEquals = new PropertyCondition(AutomationElement.NameProperty, "OurAppWindow");
var appWindow = DesktopWindow.FindFirst(TreeScope.Children, nameEquals);
// this succeeds
var idEquals = new PropertyCondition(AutomationElement.AutomationIdProperty, "ControlId");
var someItem = appWindow.FindFirst(TreeScope.Descendants, idEquals);
// this suceeds sometimes, and fails sometimes!
The problem is, the appWindow.FindFirst will sometimes fail and return null, even when the element is present. I've written a helper function which walks the UI automation tree manually and prints it out, and the element with the correct ID is present in all cases.
It seems to be related to how many other items are also being displayed in the window. If there are no other items then it always succeeds, but when there are many other complex UI elements being displayed alongside it, then the find fails.
It appears as though we're hitting some kind of internal element limit. I can't find any documented element limit mentioned for any of the automation API's - is there some way around this? I'm thinking I might have to write my own implemententation of FindFirst which does the tree walk manually itself... As far as I can tell this should work, because my tree-printer utility function does exactly that, and it's ok, but it seems like this would be unnecessary and slow :-(
Any help would be greatly appreciated

Doing the tree walk manually is probably the best way to work around this issue.
And in fact, you'll probably find that an implementation of FindFirst using tree walking will be faster that using FindFirst on an element with a large number of children. If you look at the code for AutomationElement.FindFirst in Reflector, you'll see that it works by pulling accross the automation boundary all children matching the condition, then returning the first of them. By contrast, the TreeWalker approach will only attempt to pull the single first child accross the boundary.

I had the same problem in one of my Applications I was automating. I had a custom control that was on the AdornerLayer and I was modifying the UI Automation tree so the Adorner's AutomationElement appeared as a UI Visual child to the control it was decorating instead of appearing as a child of the root for the application.
When I ran UI Spy I would get a number of errors in the Output Window stating things about an invalid parent as I navigated through its tree. I resolved a bug in my code in how I was parenting the AutomationElement for the Adorner's AutomationElement. Once I fixed the bug, UI Spy no longer displayed errors in the Output Window and I was no longer getting failures from the FindFirst method calls.
If the original poster is still monitoring this question I would ask does UI Spy have any problems navigating through your Application?

I even stuck with this problem but i only have not seen my failure.
var window = new System.Windows.Window();
window.Show();
window.Content = addControl;
GetWindow(window.Name);
I create a window an the fly and added the control as the Content of the window. My failure here was, that i showed the window, and then assigned the Content. This even fails. After hours of searching i changed it my code to this:
var window = new System.Windows.Window();
window.Content = addControl;
window.Show();
GetWindow(window.Name);
... and it works.
Michael

Related

VisualDiagnostics.VisualTreeChanged event without attached debugger?

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)

How to wait until a usercontrol is fully loaded in WPF [duplicate]

There were already a few similar questions on stackoverflow, but I haven't found the answer
I have an application that consists of several tab pages. On one of them I'm loading a list of a few dozen user controls at a time. Currently I'm doing it in Load event and because of that I have a small delay before this page is loaded. What I want to do is to make UI more responsive and fill the list after the page is fully loaded. Is there any way to track when the user control has fully loaded it's content?
VisibleChanged doesn't help too, because it fires before any other child control is shown. That causes some ugly visual effects when some of the child controls are still not visible when I'm starting to load control list.
EDIT
To make it more clear. I have some child controls on a page container and I have a list of custom controls I'm trying to load later. The problem with two approaches described in several answers below is that when I'm starting to load controls they do not let other child controls on the container to be shown and that is why I have those ugly effects (and I'm doing that with BackgroundWorker, but anyway it has to interact with the main thread to add controls to the list)
In order to make the UI more responsive, you should post yourself a message (Control.BeginInvoke), do one operation, post yourself another message. Then every time you do anything, the next step will get queued after all user messages, so user actions will get processed promptly.
One really nifty approach is to use yield return and let the compiler take care of all the closures logic:
IEnumerable AsyncLoadUI()
{
var p = new Panel();
Controls.Add(p);
yield return null;
for( int i = 0; i < 50; ++i ) {
var txt = new TextBox();
p.Controls.Add(txt);
yield return null;
}
}
override void OnLoad(EventArgs e)
{
IEnumerator tasks = AsyncLoadUI().GetEnumerator();
MethodInvoker msg = null;
msg = delegate { if (tasks.MoveNext()) BeginInvoke(msg); };
msg();
}
Take a look at my solution offered to another. They had a very similar issue. Wait until EVERYTHING finished its loading before doing a certain action, but not every time a form necessarily became "activated" or "shown". It involves attaching to the Load handler of your outermost control of interest. In your case, the tabbed page, but the example solution I provided was at the FORM level.
If the loading of this list incurs a small delay then doing this load on the UI thread will always make the form unresponsive no matter what event you do it in - changing this to be done after the form has loaded then it will just make the form unresponsive and visible as opposed to just causing a delay before the form is shown.
If there is no way to speed up the loading of the list then you will probably need to change your form loading logic so that the "heavy lifting" is instead done in a background thread so that the form remains responsive while the list is being populated. You should be aware that multithreaded code is more difficult to understand and when done incorrectly can produce bugs that are intermittant and difficult to debug and so you should definitely try to speed up your existing code first. That said if you can't speed up your list loading and the delay is unacceptable then there is not really any alternative.
If you do choose to load your list asynchronously (in a background thread) then the idea is to start a background thread (usually via a BackgroundWorker ) that does the hard work of preparing a list of items to be added - when this has finished (or failed) the form / list box is updated with the supplied list of items.
You should be able to find plenty of resources on how to do this on the internet that will cover this in more detail.

MVVM Application not Restoring State Correctly

I have built a class library that acts as a GUI framework that can be inherited by other projects. This application is based on projects Wild and Gemini.
My problem is that upon restoring Avalon Dock's layout using the standard serializer
var layoutSerializer = new XmlLayoutSerializer(manager);
where manager is type DockingManager. The manager restores and empty tab. My guess is that Caliburn Micro cannot find the stored ViewModel (named HomeViewModel). However, I am struggling to confirm this.
I believe my bootstrapper to be correct and that the MEF containers are being setup correctly to allow resolution of external types. I have debugged the project to a point where I think this issue is occurring and in the output window I can see Attach(Home) where the attach is occurring (note, "Home" is the display name of the HomeViewModel). However, I don't know what is wrong with the attach process as this is handled by MEF/Caliburn.
I am really stuck with debugging this an wondered if
Any one could offer any insightful advice as to how to proceed with the debugging process?
Anyone would be willing to take a look at the solution?
I have spent a hell of a lot of time debugging this without any luck and the problem is sufficiently esoteric and illusive as to render most posts here irrelevant to me.
Thanks for your time.
as discussed and after looking on the sample code provided, I understand that the following
HomeViewModel or can say LayoutItemBase is not supposed to be reopened as ShouldReopenOnStartup is set to false
if you close the application while leaving a document open for HomeViewModel it is restored on next start with blank view [Not OK]
Analysis
the SaveState method was correctly honoring ShouldReopenOnStartup value and was not emitting the state for the HomeViewModel but dock manager was still emitting an element for the document.
So upon next restart the LoadState does not find any stored state but a window was created as an element was present in the dock manager's layout state
<LayoutDocument Title="HomePP" IsSelected="True" IsLastFocusedDocument="True" ContentId="d716f824-cfff-4b54-8fd6-2d026a99369a" .../>
you did try to use e.Cancel property of Serialization callback to cancel the event, but seems like it is not supposed to prevent of loading a window but just simply to cancel the event if not needed.
Resolution
So the ideal approach is to close the documents which are not supposed to be restored before saving the layout
here is how I did
ShellViewmodel.cs : Line 279 method SaveState(string)
change the following code
if (!item.ShouldReopenOnStartup)
continue;
to
if (!item.ShouldReopenOnStartup)
{
//this item is not supposed to be restored so close the window before saving layout
IDocument doc = item as IDocument;
if (doc != null)
CloseDocument(doc);
continue;
}

Constrained Window render error

Basically we have two problems and they may depend so Here is the link to the second question:
We tried the constrained border layout example from the API with the difference of setting autoShow: true which ends in a broken window rendered to the top left of the document.
How can this be fixed and where is the error?
I guess you are facing the problem that the constraining container didn't finished the layout yet so that the window failed to layout itself by using the constrain target. I recommend you to call setVisible(true) on the window by using the afterFirstLayout method. The method is documented as private but based on the usage within the framework itself it should better be promoted as protected template, so you should be save using it.
I guess the afterRender wouldn't be enough cause the layout hadn't be processed yet. And the afterLayout template method would run more then once.
You may give it a try.

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.

Resources