How to (properly) cache AutomationElements for future use? - c#

In my test application, I am constantly opening and re-opening a form. Everytime the form is opened, I must get all the elements on the form into an AutomationElementCollection so that I can operate on the elements. However, it seems expensive to repeatedly get these elements (due to tree navigation/context-switches etc.).
I attempted to set a boolean around the method that gets the elements. If the method was called for the first time, it would run normally, and set the boolean to true. If the method gets called a second time it will do nothing, as the array has already been populated.
However when I try to perform operations on any AutomationElement in the array (for a second time), the elements do not seem to be available. Does closing the form somehow "disable" these elements? Do I HAVE to find these elements each time I open the form, so that they are "fresh"?
I looked at the CacheRequest way, but that seems to only pertain to accessing properties/patterns, not elements.
Here is code/error message:
AutomationElement GAP;
AutomationElementcollection GAP1;
private bool initGAP1 = false;
public void initGAP()
{
if (!initGAP1)
{
int refnum = ...;
int refnum2 = ...;
AutomationElementCollection temp = MMChildren[refnum].FindAll(TreeScope.Children, findCondition);
GAP = temp.FindAll(TreeScope.Children, findCondition)[refnum2];
GAP1 = GAP.FindAll(TreeScope.Children, findCondition); //this contains the elements I want to operate on
initGAP1 = true;
}
}
System.Windows.Automation.ElementNotEnabledException: Exception of type 'System.Windows.Automation.ElementNotEnabledException' was thrown.

You would need to re-get the Automation Elements for each new window. As I understand the UI Automation framework it gives you the means to investigate running windows. It will collect information with different techniques, depending on what kind of framework the target application uses. In your case, if you create and destroy instances of windows, they are treated as different AutomationElements since they are different windows (basically they have different window handles in the OS). Even if the underlying controlling code is the same they are different instances towards the OS, and therefore UI automation.
If you experience that you are suffering from the performance in the traversion, it might be worth considering to use the UI Automation COM API instead, that is vastly faster on some operations.

Related

Is there an issue with making a custom polling method for Selenium automation?

First of all, here's the C# code (even though the question is language-independent):
public static void PollClick(IWebElement element, int timeout = defaultTimeout, int pollingInterval = defaultPollingInterval)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.Elapsed < TimeSpan.FromSeconds(timeout))
{
try
{
element.Click();
break;
}
catch (Exception)
{
System.Threading.Thread.Sleep(pollingInterval);
}
}
}
This one is for clicking an element, but I could easily replace the click command with something else (visibility check, send text, etc). I'm setting up automation for IE, Edge, Firefox, and Chrome. I've come across a few situations where a certain web driver has a bug or the web page misbehaves for a browser (an element remains obscured, a crash with no stack trace, and other strange issues). This method has been used sparingly (once or twice) as I already have made use of the existing waits available for Selenium and have even created wrapper functions around those waits (including one that waits until an exception is no longer being thrown). Is it a bad idea to have this method handy? It did pass code review but I'm just curious as to what else I could do for anomalous situations.
There’s nothing wrong with executing such a strategy. In point of fact, the language bindings themselves do exactly that in the WebDriverWait construct. In C# (and other language bindings too, I believe) there is a generic version that is not specific to waiting on elements called DefaultWait which gives the user more control over things like what exceptions are caught and ignored, what timing interval to use, and so on. The caveat to repeating actions on the page like clicking elements is that there is a chance for the action to happen more than once, which may have unexpected side effects.
Apparently there is no issue at all in implementing a custom polling method as per your code.
But the question is Why?
The Selenium Language Bindings Java, Python, C#, Ruby internally implements the same and provides us the APIs to achieve the same. So adding one more layer to the existing layers will definitely will have an impact on the performance of your Script Execution.
Nevertheless, in general as per this discussion when you creating a new function the usual costs of making the function call are :
Push the variables onto the stack memory.
Push the return address onto the stack memory.
Branch-out to the destination function.
Creating a new stack frame in the destination function.
Now, at the end of the function the undoing of all the above :
Destroy the local objects created.
Pop the return address.
Destroy the pass-by-value parameters.
Reset the stack pointer to where it was before the parameters were pushed to stack memory.
So, creating and calling an extra function stands pretty costly in terms of System Resources. To avoid that we can easily avail the services exposed by the APIs particularly the ExpectedConditions Class as follows :
Presence of elements : An expectation for checking that all elements present on the web page that match the locator.
Visibility of elements : An expectation for checking that all elements present on the web page that match the locator are visible. Visibility means that the elements are not only displayed but also have a height and width that is greater than 0.
Click/Interactibility of element : An expectation for checking an element is visible and enabled such that you can click it.

set XAML Properties at runtime from an other C# Application (AutomationProperties.AutomationId)

given 2 applications:
1 WPF application, where not all controls have a AutomationId, and which I cannot change. In addition the application adds controls at runtime without setting the AutomationId.
1 console application which automates the above WPF application
I need that, because I want to access all elements within nearly the same amount of time. (searching for an automationelement right before using seems to differ a lot (from ms to s) in the time - depending on the amount of elements / and tree-tiers)
I would like to set AutomationIds of WPFs controls within the console application during WPFs runtime. Would be great to know, if you can think of any solution for this problem!
What I have tried until now:
1.)Reflections
Type type = element.GetType();
FieldInfo fi = type.GetField("AutomationIdProperty");
fi.SetValue(element, "x"); //Error
Error message: "Object of type 'System.String' cannot be converted to type 'System.Windows.Automation.AutomationProperty'" But I would like to hand over a value, not a property type...
if I use the following instead, it throws no error, but changes nothing in the XAML
fi.SetValue(element, AutomationElement.AutomationIdProperty);
2.)directly
AutomationElement element; // = my AutomationElement
element.Current.AutomationId = "x"; //since AutomationId is Readonly - its not possible
3.) DependencyObjects and DependencyProperties seem also promising, but I couldn't come up with an solution so far. Does someone have experience with that??
IDK how it is possible but WPF Inspector is exactly able to do what I was looking for (now I need to know how they attach to the WPF application :) ).
____OLD ANSWER____
It seems impossible to change the XAML of other programs. If the developers are "too lazy" to set the AutomationId, I've come up with a alternative solution.
The automation app iterates over all controls in the beginning, giving them unique names which are stored in a dictionary, together with their references. In case a component gets added/deleted/changed in the hierarchy, the component and their descendants get deleted in the dictionary and the app re-iterates over this sub-tree again.

Lazy<T>: "The function evaluation requires all threads to run"

I have a static class with some static properties. I initialized all of them in a static constructor, but then realized that it is wasteful and I should lazy-load each property when needed. So I switched to using the System.Lazy<T> type to do all the dirty work, and told it to not to use any of its thread safety features since in my case execution was always single threaded.
I ended up with the following class:
public static class Queues
{
private static readonly Lazy<Queue> g_Parser = new Lazy<Queue>(() => new Queue(Config.ParserQueueName), false);
private static readonly Lazy<Queue> g_Distributor = new Lazy<Queue>(() => new Queue(Config.DistributorQueueName), false);
private static readonly Lazy<Queue> g_ConsumerAdapter = new Lazy<Queue>(() => new Queue(Config.ConsumerAdaptorQueueName), false);
public static Queue Parser { get { return g_Parser.Value; } }
public static Queue Distributor { get { return g_Distributor.Value; } }
public static Queue ConsumerAdapter { get { return g_ConsumerAdapter.Value; } }
}
When debugging, I noticed a message I've never seen:
The function evaluation requires all threads to run
Before using Lazy<T>, the values were displayed directly. Now, I need to click on the round button with the threads icon to evaluate the lazy value. This happens only on my properties that are retrieving the .Value of Lazy<T>. When expanding the debugger visualizer node of the actual Lazy<T> object, the Value property simply displays null, without any message.
What does that message mean and why is it displayed in my case?
I've found an MSDN page titled "How to: Refresh Watch Values" explaining it:
When you evaluate an expression in the debugger, one of two refresh icons might appear in the Value column. One refresh icon is a circle that contains two arrows, which circle in opposite directions. The other is a circle that contains two wavy lines that resemble threads.
...
If the two threads appear, the expression was not evaluated because of a potential cross-thread dependency. A cross-thread dependency means that evaluating the code requires other threads in your application to run temporarily. When you are in break mode, all threads in your application are typically stopped. Allowing other threads to run temporarily can have unexpected effects on the state of your program and causes the debugger to ignore events such as breakpoints.
I'd still like a better explanation if anyone can give it. Questions that this doesn't answer include: What kind of evaluation requires all threads to run? How does the debugger identify such a case? What exactly happens when you click the thread refresh icon?
EDIT: I think I've stumbled across the answer when examining Lazy<T> under ILSpy (for a completely different reason). The getter of the Value property has a call to a Debugger.NotifyOfCrossThreadDependency(). MSDN has this to say:
[...] performing a function evaluation typically requires freezing all threads except for the thread that is performing the evaluation. If the function evaluation requires execution on more than one thread, as might occur in remoting scenarios, the evaluation will block. The NotifyOfCrossThreadDependency notification informs the debugger that it has to release a thread or abort the function evaluation.
So basically, to prevent the annoying case where you try to evaluate some expression and Visual Studio just hangs for 30 seconds and then informs you that "a function evaluation has timed out", the code has a chance to inform the debugger that it must unfreeze other threads for the evaluation to succeed or otherwise the evaluation will block forever.
Since running other threads may disrupt your debugging session, as usually when you evaluate an expression all other threads are kept frozen, the debugger doesn't automatically proceeed and warns you before letting you jump down the rabbit hole.
My guess would be that the debugger is trying to avoid influencing the application state by loading the properties for you.
You have to remember, that lazy load only happens when you reference/access the properties.
Now, in general, you do not want debugging to affect the state of the application, otherwise that will not give an accurate representation of what the application state should be (Think multi threaded apllications and debugging)
Have a look at Heisenbug
I struggled with this for hours and found the original error message about requiring all threads to run misleading. I was accessing an existing database from a new solution and creating new Entity Framework entity POCOs and data access layers within the new solution to access and map to the DB.
I did two things initially wrong. I didn't properly define the primary key in my C# entity POCO, and the table I was accessing had a unique schema in the DB (it was not dbo.tablename but edi.tablename).
In my DbContext.cs file, I did the following to map the table under the right schema. Once I corrected these things the error went away and it worked just fine.
protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
{
base.OnModelCreating(dbModelBuilder);
dbModelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
dbModelBuilder.Entity<TableName>().ToTable("TableName", schemaName: "EDI");
}
Create a local variable and assign it the value you want to inspect.
This will let you inspect it because the debugger doesn't have to worry about whether or not accessing the property will disturb your application, because it will have already accessed it when assigning it to the local variable.
For me, I found it didn't matter if I had this.Configuration.LazyLoadingEnabled = false; or = true;, if I had the line in my DBContext or not. It seems to occur, from my reading up on the problem, because a thread is occurring & the debugger wants permission to run it/is warning you before it spurs it. Apparently, in some cases, you can even allow it to proceed according to MUG4N's answer here: Visual Studio during Debugging: The function evaluation requires all threads to run
But what I found was I could get around the issue.
2 options:
Add .ToList() on your Queues:
var q = db.Queues.OrderBy(e => e.Distributor).ToList();
I found a workaround by selecting Non-Public Members > _internalQuery > ObjectQuery > Results View.

List.Add(this) inside of a class

I created a class awhile back. I used List.Add(this) inside of the class so I could access the controls I created later. It seemed to be very useful and I do not know how to create controls (more than one in the same parent control without a predefined limit) and access them later.
I was looking for Add(this) on the internet and couldn't find anymore information on it.
Is this a large resource hog or ineffective? Why can't I find more information on it? It seems very useful.
public class GlobalData
{
private static List<Member> _Members;
public partial class ChildrenPanel
{
private static List<ChildrenPanel> _ListCP = new List<ChildrenPanel>();
//X and Y position Panel | Container is the control recieving the Control
public void CreatePanel(int X, int Y, Panel Container)
{
//
// pnlStudent
//
_pnlStudent.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
_pnlStudent.Controls.Add(_lblCLastName);
_pnlStudent.Controls.Add(_lblCFirstName);
_pnlStudent.Controls.Add(_lblGrade);
_pnlStudent.Controls.Add(_lblSelected);
_pnlStudent.Controls.Add(_lblSeason);
_pnlStudent.Controls.Add(_lblAvailable);
_pnlStudent.Controls.Add(_lblGender);
_pnlStudent.Controls.Add(_ddlGrade);
_pnlStudent.Controls.Add(_ddlSelectedSports);
_pnlStudent.Controls.Add(_ddlAvailableSports);
_pnlStudent.Controls.Add(_ddlSeason);
_pnlStudent.Controls.Add(_rdbFemale);
_pnlStudent.Controls.Add(_rdbMale);
_pnlStudent.Controls.Add(_btnRemoveChild);
_pnlStudent.Controls.Add(_btnRemoveSport);
_pnlStudent.Controls.Add(_btnAddSport);
_pnlStudent.Controls.Add(_txtCLastName);
_pnlStudent.Controls.Add(_txtCFirstName);
_pnlStudent.Location = new System.Drawing.Point(X, Y);
_pnlStudent.Name = "pnlStudent";
_pnlStudent.Size = new System.Drawing.Size(494, 105);
//Still playing with the tab index
_pnlStudent.TabIndex = 10;
// Adds controls to selected forms panel
Container.Controls.Add(_pnlStudent);
// Creates a list of created panels inside the class
ListCP.Add(this);
}
Just make sure that you Remove the instance again when it's no longer needed, otherwise the List holding a reference to it will keep it in memory forever (Welcome to memory leaks in .NET after all).
I may revise this answer once I see some code, but my initial response is that it is not a resource hog. As to whether it is effective or not, some example code will be required.
Adding an object to a collection does not take up a large amount of resources because you are simply adding a reference to the object into the collection. You still only have a single object, but two (or more) variables that point to that object, so the only extra resources you are using are the minimal memory used by the references.
If your List is static or otherwise globally available, then you're doing something very bad.
ASP.Net is structured such that every request to your page - including postbacks - from every user results in a new instance of the page class. that's a lot of page instances. If references to all these instances are saved somewhere, the instances can never be garbage collected. You've created something analogous to a memory leak and you'll quickly find yourself running out of resources after you deploy to production.
The really dangerous thing here is that if you only do functional testing and no load testing the problem will likely not show up during your tests at all, because it will work fine for a few hundred (maybe even thousand) requests before blowing up on you.
If you're worried about dynamic controls, there are several better ways to handle this:
Put a fixed limit on the maximum number of controls you will allow, and add all of them to the page up front. Then only show/render them (toggled via the .Visible property) as you need them.
Make it data-driven. Rather than dynamically add a control, insert something to a database table and then bind a query on that table to a repeater or other data control (my preferred method).
Just make sure you're recreating every dynamic control you need at the right place (Pre-Init) in the page lifecycle.

C# Running IronPython On Multiple Threads

I have a WPF app that controls audio hardware. It uses the same PythonEngine on multiple threads. This causes strange errors I see from time to time where the PythonEngines Globals dictionary has missing values. I am looking for some guidance on how to debug/fix this.
The device has multiple components [filter's, gain's, etc.]. Each component has multiple controls [slider's,togglebutton's, etc.].
Everytime a user changes a control value a python script (from the hardware vendor) needs to run. I am using IronPython 1.1.2(PythonEngine.Execute(code)) to do this.
Every component has a script. And each script requires the current values of all controls (of that component) to run.
The sequence is - user makes change > run component script > send results to device > check response for failure. This whole cycle takes too long to keep the UI waiting so everytime something changes I do something like component.begininvoke(startcycle).
Startcycle looks something like this -
PyEngine Engine = PyEngine.GetInstance(); // this is a singleton
lock(component) // this prevents diff controls of the same component from walking over each other
{
Engine.runcode(...)
}
When different component.begininvokes happen close to each other there are chances where engine.runcode is happening on different threads at the same time. It looks like I need to get rid of the component.begininvoke but that would make things crawl. Any ideas?
You probably want to create a EngineModule for each execution and execute the code against that. Then all of the code will run against a different set of variables. You also probably want to get a CompiledCode object and actually execute that against the new EngineModule each time because engine.Execute will need to re-compile it each time.

Categories