我们使用棱镜和WPF来构建应用程序。 最近,我们开始使用UI自动化(UIA)来测试我们的应用程序。 但一些奇怪的行为时有发生,我们运行UIA测试。 下面是简单的外壳:
<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>
在我们的应用程序,我们使用图层( Popup
和ErrorPopup
)隐藏MainViewArea,拒绝访问的控制。 要显示Popup
,我们用下一个方法:
//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;
}
}
与此类似,我们显示ErrorPopup
在我们的应用程序的所有元素:
// 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);
}
}
神秘主义者...
当我们运行它,因为用户这样做(在应用程序图标双击),我们可以看到两个自定义控件(使用AutomationElement.FindFirst
方法,或通过视觉UI自动化验证 )。 但是,当我们使用UI自动化测试启动- ErrorPopup
在前看不见从控件的树。 我们试图启动这样的应用程序:
System.Diagnostics.Process.Start(pathToExeFile);
我认为,我们错过了什么。 不过什么?
编辑#1
作为@chrismead说,我们想跑我们的应用程序UseShellExecute
标志设置为true,但这并不能帮助。 但是,如果我们开始从CMD行应用程序,并手动点击按钮, Popup
和ErrorPopup
是自动化控制树可见。
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();
我们的一个建议是,当我们使用方法FindAll
或FindFirst
搜索按钮,点击,窗口莫名其妙缓存的UI自动化状态,并且不更新它。
编辑#2我们已经发现,棱镜库是扩展方法IRegionManager.RegisterViewWithRegion(RegionNames.OurRegion, typeof(Views.OurView))
有一些奇怪的行为。 如果我们停止使用它,这解决我们的问题格外。 现在我们能看到ErrorView和任何形式的视图PopupContentControl
,和应用程序更新UIA元素树结构。 但是,这不是一个答案 - “只要停止使用该功能”!
在MainViewArea
我们有一个ContentControl
,这将更新其内容根据用户的行为,我们都能够看到只有第一个加载的UserControl
到ContentControl.Content
财产。 这是这样进行的:
IRegionManager regionManager = Container.Resolve<IRegionManager>();
regionManager.RequestNavigate(RegionNames.MainContentRegion, this.Uri);
如果我们改变了看法,没有更新将在UI Automation树进行 - 第一加载视图将在它来代替。 但是,在视觉上我们观察到另一个View
,并WPFInspector正确显示它(它的节目不是UI Automation树),但Inspect.exe -不是。
同时我们建议,即窗口使用某种缓存是错误的 - 缓存在UI自动化客户端,我们必须明确地打开,但我们不这样做。