当应用程序通过UI自动化测试启动时,ContentControl不可见,但在用户启动应用程序时可以看到ContentControl [英] ContentControl is not visible when application starts via UI Automation test, but its visible when application starts by user

查看:369
本文介绍了当应用程序通过UI自动化测试启动时,ContentControl不可见,但在用户启动应用程序时可以看到ContentControl的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用棱镜和WPF来构建应用程序。最近我们开始使用UI自动化(UIA)来测试我们的应用程序。但是当我们运行UIA测试时,会发生一些奇怪的行为。这是简化的shell:

 < Grid> 
< Grid.ColumnDefinitions>
< ColumnDefinition Width =*/>
< /Grid.ColumnDefinitions>
< Grid.RowDefinitions>
< RowDefinition Height =*/>
< /Grid.RowDefinitions>

< TextBlock
Grid.Row =0Grid.Column =0
Name =loadProgressText
VerticalAlignment =CenterHorizo​​ntalAlignment =中心
文本=正在加载,请稍候.../>

< Border
Grid.Row =0
x:Name =MainViewArea>
< Grid>
...
< / Grid>
< / Border>

<! - Popup - >
< ContentControl
x:Name =PopupContentControl
Grid.Row =0
prism:RegionManager.RegionName =PopupRegion
Focusable =False >
< / ContentControl>

<! - ErrorPopup - >
< ContentControl
x:Name =ErrorContentControl
Grid.Row =0
prism:RegionManager.RegionName =ErrorRegion
Focusable =False >
< / ContentControl>
< / Grid>

在我们的应用中,我们使用图层( Popup ErrorPopup )隐藏 MainViewArea ,以拒绝对控件的访问。要显示 Popup ,我们使用下一个方法:

  //在构造函数中当前的ViewModel我们将_popupRegion实例存储到局部变量中:
_popupRegion = _regionManager.Regions [PopupRegion];
// ---

private readonly Stack< UserControl> _popups = new Stack< UserControl>();
public void ShowPopup(UserControl popup)
{
_popups.Push(弹出);

_popupRegion.Add(PopupView);
_popupRegion.Activate(PopupView);
}

public UserControl PopupView
{
get
{
if(_popups.Any())
return _popups。窥视();
返回null;
}
}

与此类似,我们显示 ErrorPopup 我们应用程序的所有元素:

  //在构造函数中,我们存储_errorRegion:
_errorRegion = _regionManager.Regions [ErrorRegion]
// ---

private UserControl _error_popup;

public void ShowError(UserControl popup)
{
if(_error_popup == null)
{
_error_popup = popup;
_errorRegion.Add(_error_popup);
_errorRegion.Activate(_error_popup);
}
}

Mistics ...



当用户执行它(双击应用程序图标)时,我们可以看到两个自定义控件(使用 AutomationElement.FindFirst 方法,或通过可视化UI自动化验证)。但是当我们使用UI自动化测试开始使用 - $ code> ErrorPopup 从控件树中消失。我们试图启动这样的应用程序:

  System.Diagnostics.Process.Start(pathToExeFile); 

我想我们错过了一些东西。但是什么?



编辑#1



正如@chrismead所说,运行我们的应用程序,使用 UseShellExecute 标志设置为true,但这没有帮助。但是,如果我们从 cmd 行开始应用,并手动点击按钮, Popup ErrorPopup 在自动化控件树中可见

 线程appThread = new Thread(delegate()
{
_userAppProcess = new Process();
_userAppProcess.StartInfo.FileName = pathToExeFile;
_userAppProcess.StartInfo.WorkingDirectory = System.IO.Directory.GetCurrentDirectory();
_userAppProcess.StartInfo.UseShellExecute = true ;
_userAppProcess.Start();

});
appThread.SetApartmentState(ApartmentState.STA);
appThread.Start();

我们的建议之一是当我们使用方法 FindAll FindFirst 搜索按钮以单击,窗口以某种方式缓存其UI自动化状态,并且不更新它。



编辑#2
我们找到了棱镜库的扩展方法 IRegionManager.RegisterViewWithRegion(RegionNames.OurRegion,typeof(Views.OurView))有一些奇怪的行为。如果我们停止使用它,这将解决我们的问题。现在我们可以在 PopupContentControl 中看到ErrorView和任何类型的视图,并且应用程序更新UIA元素树结构。但是这不是一个答案 - 只是停止使用这个功能!



MainViewArea 我们有一个 ContentControl ,它根据用户操作更新内容,我们只能看到第一个加载的 UserControl ContentControl.Content 属性。这样执行:

  IRegionManager regionManager = Container.Resolve< IRegionManager>(); 
regionManager.RequestNavigate(RegionNames.MainContentRegion,this.Uri);

如果我们更改视图,在UI自动化树中不会执行更新 - 第一个加载的视图将换成它但是在视觉上我们观察到另一个查看 WPFInspector 正确显示它(它不显示UI自动化树),但Inspect.exe - 不是。



我们的建议窗口使用某种缓存是错误的 - 在UI Automation客户端中缓存,我们必须明确地打开,但是我们不这样做。

解决方案

我很抱歉我错过了一些细节,那是答案的关键。我认为这不重要。无论如何,



我们使用 WPF DevExpress 控件库中的 NavBar / strong>即可。事实证明,当 NavBar 存在时,动态创建的视图不会出现在UI自动化树上。当从窗口中删除它时,可以看到所有动态加载的视图。对于我来说, NavBar - 对于我来说还是很流行的。



如果NavBar存在,这里有一个很好的例子来看看发生了什么或不在窗口(需要DevExpress)。



MainWindow.xaml:

 < Window xmlns:dxn =http://schemas.devexpress.com/winfx/2008/xaml/navbar
x:Class =Test.MainWindow
xmlns =http ://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
Title =MainWindow Height =350Width =525
>
< Grid Name =ContentGrid>
< Grid.ColumnDefinitions>
< ColumnDefinition Width =Auto/>
< ColumnDefinition />
< /Grid.ColumnDefinitions>

< Grid.RowDefinitions>
< RowDefinition>< / RowDefinition>
< RowDefinition>< / RowDefinition>
< /Grid.RowDefinitions>
<! - 注释NavBar可以在UI自动化树中查看动态控件 - >
< dxn:NavBarControl Name =asdasd>
< dxn:NavBarControl.Groups>
< dxn:NavBarGroup Header =asdasdasdasd/>
< / dxn:NavBarControl.Groups>
< / dxn:NavBarControl>
< TextBox Grid.Column =1Name =StatictbText =静态在ui自动化树中可见/>
< Button Grid.Row =1Content =创建控件Height =25Click =Button_Click/>
< / Grid>
< / Window>

MainWindow.xaml.cs

  public partial class MainWindow:Window 
{
public MainWindow()
{
InitializeComponent();
}

private void Button_Click(object sender,RoutedEventArgs e)
{
TextBox tb = new TextBox();
Grid.SetRow(tb,1);
Grid.SetColumn(tb,1);
tb.Text =动态不可见,如果NavBar在这里...;
ContentGrid.Children.Add(tb);
}
}

修改



根据 DevExpress答案< a>在他们的支持网站上:


创建对等体后,监听自动化事件可能会导致性能问题。我们决定清除自动化事件的调用列表来解决。在具体情况下,您需要禁用清除。要做到这一点,请在Window构造函数中将静态DevExpress.Xpf.Core.ClearAutomationEventsHelper.IsEnabled属性设置为False。


问题。


We are using the prism and WPF to build application. Recently we started using UI Automation (UIA) to test our app. But some strange behavior occurred when we run UIA test. Here's simplified shell:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>    
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <TextBlock 
        Grid.Row="0" Grid.Column="0"
        Name="loadingProgressText"
        VerticalAlignment="Center" HorizontalAlignment="Center"
        Text="Loading, please wait..."/>

    <Border
        Grid.Row="0" 
        x:Name="MainViewArea">
        <Grid>
            ...
        </Grid>
    </Border>

    <!-- Popup -->
    <ContentControl 
        x:Name="PopupContentControl"
        Grid.Row="0" 
        prism:RegionManager.RegionName="PopupRegion"
        Focusable="False">
    </ContentControl>

    <!-- ErrorPopup -->
    <ContentControl 
        x:Name="ErrorContentControl"
        Grid.Row="0" 
        prism:RegionManager.RegionName="ErrorRegion"
        Focusable="False">
    </ContentControl>
</Grid>

In our app, we use layers (Popup and ErrorPopup) to hide MainViewArea, to deny access to the controls. To show Popup, we use next method:

    //In constructor of current ViewModel we store _popupRegion instance to the local variable:
    _popupRegion = _regionManager.Regions["PopupRegion"];
    //---

    private readonly Stack<UserControl> _popups = new Stack<UserControl>();
    public void ShowPopup(UserControl popup)
    {
        _popups.Push(popup);

        _popupRegion.Add(PopupView);
        _popupRegion.Activate(PopupView);
    }

    public UserControl PopupView
    {
        get
        {
            if (_popups.Any())
                return _popups.Peek();
            return null;
        }
    }

Similar to this, we show ErrorPopup over all elements of our application:

    // In constructor we store _errorRegion:
    _errorRegion = _regionManager.Regions["ErrorRegion"]
    // --- 

    private UserControl _error_popup;

    public void ShowError(UserControl popup)
    {
        if (_error_popup == null)
        {
            _error_popup = popup;
            _errorRegion.Add(_error_popup);
            _errorRegion.Activate(_error_popup);
        }
    }

Mistics...

When we run it as users do it (double click on app icon), we can see both custom controls (using AutomationElement.FindFirst method, or through Visual UI Automation Verify). But when we start it using UI Automation test - ErrorPopup disapears from the tree of the controls. We trying to start the application like this:

System.Diagnostics.Process.Start(pathToExeFile);

I think that we missed something. But what?

Edit #1

As @chrismead said, we tried to run our app with UseShellExecute flag set to true, but this does not help. But if we start app from cmd line, and manually click the button, Popup and ErrorPopup are visible in automation controls tree.

    Thread appThread = new Thread(delegate()
        {
            _userAppProcess = new Process();
            _userAppProcess.StartInfo.FileName = pathToExeFile;
            _userAppProcess.StartInfo.WorkingDirectory = System.IO.Directory.GetCurrentDirectory();
            _userAppProcess.StartInfo.UseShellExecute = true;
            _userAppProcess.Start();

        });
        appThread.SetApartmentState(ApartmentState.STA);
        appThread.Start();

One of our suggestion is when we use method FindAll or FindFirst to search the button to click, window somehow cached its UI Automation state, and does not update it.

Edit #2 We have find, that extension method of prism library IRegionManager.RegisterViewWithRegion(RegionNames.OurRegion, typeof(Views.OurView)) have some strange behavior. If we stopped use it, this solve our problem particulary. Now we able to see ErrorView and any kind of view in PopupContentControl, and application updates UIA elements tree structure. But this is not an answer - "Just stop use this feature"!

In MainViewArea we have a ContentControl, which updates it content depending on user actions, and we are able to see only the first loaded UserControl to that ContentControl.Content property. This is performed like this:

IRegionManager regionManager = Container.Resolve<IRegionManager>();
regionManager.RequestNavigate(RegionNames.MainContentRegion, this.Uri);

And if we change the view, no updates will performed in UI Automation tree - the first loaded view will be in it instead. But visually we observe another View, and WPFInspector shows it properly (its show not a UI Automation tree), but Inspect.exe - not.

Also our suggestion that window use some kind of caching is wrong - caching in UI Automation client we have to turn on explicitly, but we don't do it.

解决方案

I'm sorry that I've missed some detail, that was the key to the answer. I think that it was not important thing. Anyway.

We used NavBar from DevExpress controls library for WPF. What turns out, is when NavBar is present, dynamically created views are not appears on the UI Automation tree. When remove it from the window, there was an ability to see all dynamically loaded views. What does the NavBar - still mistic for me.

Here bright example to see what happened, if NavBar is present or absent on the Window (DevExpress is required).

MainWindow.xaml:

<Window xmlns:dxn="http://schemas.devexpress.com/winfx/2008/xaml/navbar"
        x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        >
    <Grid Name="ContentGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <!--Comment NavBar to see dynamic control in UI Automation tree-->
        <dxn:NavBarControl Name="asdasd">
            <dxn:NavBarControl.Groups>
                <dxn:NavBarGroup Header="asdasdasdasd" />
            </dxn:NavBarControl.Groups>
        </dxn:NavBarControl>
        <TextBox Grid.Column="1" Name="Statictb" Text="static is visible in ui automation tree" />
        <Button Grid.Row="1" Content="Create controls" Height="25"  Click="Button_Click"/>
    </Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        TextBox tb = new TextBox();
        Grid.SetRow(tb, 1);
        Grid.SetColumn(tb, 1);
        tb.Text = "dynamic is not visible, if NavBar here...";
        ContentGrid.Children.Add(tb);
    }
}

Edit

According to the DevExpress answer on their support site:

After a peer is created, listening of automation events may cause performance issues. We have decided to clear invocation lists of automation events to resolve it. In your specific situation, you need to disabling clearing. To do it, please set the static DevExpress.Xpf.Core.ClearAutomationEventsHelper.IsEnabled property to False in the Window constructor.

This solve the problem.

这篇关于当应用程序通过UI自动化测试启动时,ContentControl不可见,但在用户启动应用程序时可以看到ContentControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆