是否可以为整个WPF 4.0应用程序禁用UI自动化?

时间:2013-06-25 12:36:47

标签: .net wpf ui-automation microsoft-ui-automation

我们正在开发一个供内部使用的WPF 4.0应用程序。
在某些客户端,由于UI自动化,我们遇到了巨大的性能问题 (这些客户端的软件安装像平板电脑服务笔,触摸,...)。

这是WPF 4.0的已知问题,例如:


我们已经能够在规格非常有限的机器上重现这个问题。 在此机器上打开WPF窗口需要:

  • 00:00:02 - 未安装任何UI自动触发软件
  • 00:01:41 - 安装了UI自动触发软件(RoboForm用于此测试)
  • 00:00:09 - 安装了UI自动触发软件,并应用了修补程序KB2484841

正如您所看到的,安装修补程序KB2484841是一项巨大的改进,但仍然没有安装ui Automation触发软件时运行速度快。
此外,我们无法控制在客户端安装哪些软件,因此很难为所有客户端推出此修复程序。


因此,是否可以为整个WPF应用程序“关闭”UI自动化? 我知道它可以在每个UserControl的基础上完成,但它是否可以作为一个整体的应用程序?

我已尝试过this帖子中提供的代码,但没有成功。


谢谢你的时间,
柯恩

5 个答案:

答案 0 :(得分:13)

我们遇到了问题中提到的完全相同的问题,其中UI自动化客户端正在影响我们的WPF应用程序的性能。

在尝试了所有热修复和解决方法后,我们终于找到了解决方案。每个UI控件都有一个AutomationPeer对象,它公开当前控件及其子控件的属性。 UI自动化客户端使用这些AutomationPeer对象来获取有关UI控件的信息。 WPF中的大多数UI控件都有内置的自动化对等类,我们也可以创建自定义对等类。

以下是自定义自动化同级类。请注意,在GetChildrenCore方法中,它返回一个空列表而不是实际子控件列表。

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>();
    }
}

然后在主窗口中,覆盖OnCreateAutomationPeer方法:

protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
{
    return new CustomWindowAutomationPeer(this);
}

现在,当UI自动化客户端尝试获取主窗口的子控件时,它会返回一个空列表,因此无法遍历其余控件。

有关详细信息,请参阅此MSDN article

答案 1 :(得分:3)

我们在 DevExpress 控件中遇到了同样的问题。解决方法代码对我们都没有帮助。而且我认为没有任何“切换”来禁用UI自动化。但是自从上一版本DevExpress有一些神奇的 ClearAutomationEventsHelper 类可以做一些技巧。据我所知,我们的想法是清除AutomationEvents.Count属性(通过Reflection)以获取导致问题的控件。例如,他们在其基本控件(来自MeasureOverride)或每次创建自动化对等体时调用此方法。

如果您使用DevExpress,此类可以成为您项目的灵丹妙药。我们完全可以避免WPF 4.0项目中UI自动化问题的副作用,客户真的很高兴。

答案 2 :(得分:1)

尝试一些货物崇拜节目:

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);
  }

答案 3 :(得分:0)

看一下这篇文章:

Preventing UI Automation access to an application

据说UIAccess flag可以解决你的问题!

Chack也是这篇文章,以便创建一个可信证书:

Problem with manifest and uiAccess set to true...

答案 4 :(得分:-1)

您是否尝试过以下方法:

  1. 只有在机器中运行任何自动化客户端(如屏幕阅读器,平板电脑中的tabtip等)时,才会触发自动化代码。因此,摆脱这种情况的一种方法是关闭任何自动化客户端应用程序。

  2. 如果一个不可行,那么另一个选择是,UIElementHelper.InvalidateAutomationAncestors只有在应用程序的自动化树稀疏时才会花费更长的时间(如果使用自定义窗口自动化对等方禁用了楼宇自动化树,则会发生)并且可视化树是稠密。所以另一种解决方案是禁用任何自定义自动化代码,并允许WPF构建完整的自动化树。这样可以加快UIElementHelper.InvalidateAutomationAncestors的速度。

  3. 这是我发现的关于你的问题的内容,他们也表示他们已经知道这个问题,并会尝试修复它。