我们正在开发一个供内部使用的WPF 4.0应用程序。
在某些客户端,由于UI自动化,我们遇到了巨大的性能问题
(这些客户端的软件安装像平板电脑服务笔,触摸,...)。
这是WPF 4.0的已知问题,例如:
我们已经能够在规格非常有限的机器上重现这个问题。
在此机器上打开WPF窗口需要:
正如您所看到的,安装修补程序KB2484841是一项巨大的改进,但仍然没有安装ui Automation触发软件时运行速度快。
此外,我们无法控制在客户端安装哪些软件,因此很难为所有客户端推出此修复程序。
因此,是否可以为整个WPF应用程序“关闭”UI自动化? 我知道它可以在每个UserControl的基础上完成,但它是否可以作为一个整体的应用程序?
我已尝试过this帖子中提供的代码,但没有成功。
谢谢你的时间,
柯恩
答案 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也是这篇文章,以便创建一个可信证书:
答案 4 :(得分:-1)
您是否尝试过以下方法:
只有在机器中运行任何自动化客户端(如屏幕阅读器,平板电脑中的tabtip等)时,才会触发自动化代码。因此,摆脱这种情况的一种方法是关闭任何自动化客户端应用程序。
如果一个不可行,那么另一个选择是,UIElementHelper.InvalidateAutomationAncestors只有在应用程序的自动化树稀疏时才会花费更长的时间(如果使用自定义窗口自动化对等方禁用了楼宇自动化树,则会发生)并且可视化树是稠密。所以另一种解决方案是禁用任何自定义自动化代码,并允许WPF构建完整的自动化树。这样可以加快UIElementHelper.InvalidateAutomationAncestors的速度。
这是我发现的关于你的问题的内容,他们也表示他们已经知道这个问题,并会尝试修复它。