We are developing a WPF 4.0 application for internal use.
On some clients, we are experiencing huge performance issues due to UI automation
(these clients have software i
We hit the exact same issue mentioned in the question, where a UI automation client was impacting the performance of our WPF
application.
After trying all the hot fixes and workarounds, finally we found a solution. Each UI control has an AutomationPeer
object that exposes the properties of the current control and its child controls. The UI automation client uses these AutomationPeer
objects to get the information about the UI controls. There are built-in automation peer class for most of the UI controls in WPF
and we can also create a custom peer class.
The following is a custom automation peer class. Note that in the GetChildrenCore
method, it is returning an empty list instead of the list of actual child controls.
public class CustomWindowAutomationPeer : FrameworkElementAutomationPeer
{
public CustomWindowAutomationPeer(FrameworkElement owner) : base(owner) { }
protected override string GetNameCore()
{
return "CustomWindowAutomationPeer";
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Window;
}
protected override List<AutomationPeer> GetChildrenCore()
{
return new List<AutomationPeer>();
}
}
Then in your main window, override the OnCreateAutomationPeer
method:
protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
{
return new CustomWindowAutomationPeer(this);
}
Now when the UI automation client tries to get the child controls of the main window, it gets back an empty list and so it cannot iterate through the rest of the controls.
Refer this MSDN article for more details.
Have you tried the following things:
Automation code will be triggered only if there are any automation clients ( like screen reader, tabtip in tablet pcs, etc) running in the machine. So one way to get out of this situation is to close any of those automation client apps.
If one is not feasible then an alternative is, UIElementHelper.InvalidateAutomationAncestors will take longer time only if automation tree for the app is sparse ( happens if had disabled building automation tree using custom window automation peer) and visual tree is dense. So another solution is disable any custom automation code and allow WPF to build complete automation tree. This should speed up UIElementHelper.InvalidateAutomationAncestors as well.
This is what I've found regarding your problem, also they said that they are aware of this issue and will try to fix it.
Take a a look at this article :
Preventing UI Automation access to an application
It is said that UIAccess flag
may be able to solve your problems!
Chack also this article so as to create a Trusted certificate :
Problem with manifest and uiAccess set to true...
We had the same issue with DevExpress controls. Neither workaround code helps to us. And I suppose that there is not any "switch" to disable UI Automation. But since last versions DevExpress have magic ClearAutomationEventsHelper class that do some tricks. As I understood, the idea is to clear AutomationEvents.Count property (via Reflection) for controls that cause issue. E.g., they call this method in their base controls (from MeasureOverride), or each time automation peer created.
If you use DevExpress, this class can be silver bullet for your project. We able totally avoid side effects of UI Automation issues in our WPF 4.0 projects and customers were really happy.
Try some cargo-cult programming:
WindowInteropHelper helper = new WindowInteropHelper(mainWindow);
AutomationElement mainWindowAutomationElement = AutomationElement.FromHandle(helper.Handle);
Automation.Automation.AddStructureChangedEventHandler(mainWindowAutomationElement, TreeScope.Descendants, AutomationFix);
void AutomationFix(object sender, StructureChangedEventArgs e)
{
AutomationElement element = sender as AutomationElement;
Automation.Condition condition = new PropertyCondition(AutomationElement.NameProperty, "!!");
AutomationElement automationElement = element.FindFirst(TreeScope.Children, condition);
}