【问题标题】:Can UI Automation be disabled for an entire WPF 4.0 app?可以为整个 WPF 4.0 应用禁用 UI 自动化吗?
【发布时间】:2013-06-22 06:17:37
【问题描述】:

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

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


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

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

如您所见,安装修补程序 KB2484841 是一个巨大的改进,但仍然不如没有安装 ui 自动化触发软件的运行速度。
此外,我们对在客户端安装哪些软件没有太多控制权,因此很难为所有客户端推出此修复程序。


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

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


感谢您的宝贵时间,
科恩

【问题讨论】:

  • UI 自动化用于辅助功能。因此,如果客户安装了由于任何残疾而需要的软件,您想阻止他们使用您的软件吗?接受一些慢下来,至少检测“正在使用自动化,未安装修补程序”并提示用户(一次,或每隔几次重新启动)他们应该安装它不是更好吗?
  • 这是一个内部业务应用程序;此类场景不受支持且超出此应用程序的范围。
  • 不支持...直到您找到第一位残疾员工。这是 WPF 做得好的一件事——它确保所有边缘情况,如残疾和本地化以及字符串安全,都在你需要它们的时候连接起来。但这种准备是有代价的。
  • 问题是 - 微软从未摆脱 UIAutomation 的最后几个错误。它会导致应用程序崩溃,减慢速度,导致无穷无尽的问题,并且故意使其难以禁用。这是一个功能,最好以任何可能的方式完全禁用它,至少在 Microsoft 解决未解决的问题之前。

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


【解决方案1】:

我们遇到了问题中提到的完全相同的问题,即 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

【讨论】:

  • 只是发帖说这解决了我的问题,但只有使用 WPF ToolKit Datagrid 的平板电脑例外。错误和异常堆栈的最顶部是:` System.InvalidOperationException:对自动化对等 API 的递归调用无效。在 System.Windows.Automation.Peers.AutomationPeer.GetChildren()` 使用此系统返回 AutomationPeer 的新派生实例解决了我的问题,现在一切正常。谢谢。
  • 使用方法:在任何 WPF 应用程序中搜索“Window 继承的所有 .xaml 文件。然后,在后面的代码(“.xaml.cs”文件)中,添加覆盖OnCreateAutomationPeer() 的代码。这是一个分部类,因此您还可以添加: Window 以明确该分部类继承自Window
  • 这不会阻止组合框飞出或工具提示弹出窗口生成自动化对等点并导致应用程序的其余部分产生自动化对等点
【解决方案2】:

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

如果您使用 DevExpress,这个类可以成为您项目的灵丹妙药。我们能够在 WPF 4.0 项目中完全避免 UI 自动化问题的副作用,客户非常满意。

【讨论】:

  • 为了正确起见,DevExpress 类被命名为ClearAutomationEventsHelper
  • 正是我要找的东西! ClearAutomationEventsHelper.IsEnabled=False 消除了我们在 DevExpress GridControl 中遇到的一些内存泄漏。
【解决方案3】:

尝试一些货物狂热的编程:

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

【讨论】:

  • 此代码已在一段时间前作为答案发布,然后被删除。那是你吗?我再说一遍:虽然这种奇怪的解决方法可能会帮助一些已经运行自动化客户端的人,但它肯定不会禁用 UI 自动化。
  • 不,之前发布的不是我。在微软决定是否要提供禁用 UI 自动化之前,您将不得不接受变通方法,我怀疑他们会这样做。
【解决方案4】:

看看这篇文章:

Preventing UI Automation access to an application

据说UIAccess flag或许能解决你的问题!

也可以查看这篇文章以创建受信任的证书:

Problem with manifest and uiAccess set to true...

【讨论】:

  • UIAccess 标志默认为 false。
  • 添加 UI 访问不会解决自动化问题。 UI Access 用于提高辅助功能程序(如讲述人等)的权限,以便他们可以访问否则会被阻止的程序的 UI。
【解决方案5】:

您是否尝试过以下方法:

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

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

这是我发现的关于您的问题的信息,他们也说他们知道这个问题并将尝试解决它。​​

【讨论】:

  • 您从中复制此答案的MSDN thread 链接在此问题中链接的问题之一中。你不认为这个问题的作者已经读过吗?此外,虽然它提供了一些关于如何改善这种情况的提示,但并没有真正回答问题。
猜你喜欢
  • 2015-01-07
  • 1970-01-01
  • 1970-01-01
  • 2021-06-23
  • 2010-11-28
  • 1970-01-01
  • 2015-12-22
  • 2011-09-16
  • 2021-01-03
相关资源
最近更新 更多