我們使用prism和WPF來構建應用程序。最近我們開始使用UI自動化(UIA)來測試我們的應用程序。但是當我們運行UIA測試時發生了一些奇怪的行爲。這裏的簡化殼:當應用程序通過UI自動化測試啓動時ContentControl不可見,但當應用程序由用戶啓動時它是可見的
<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);
}
}
Mistics ...
當我們運行就像用戶這樣做(雙擊應用程序圖標),我們可以看到兩個自定義控件(使用AutomationElement.FindFirst
方法或通過Visual UI Automation Verify)。但是,當我們使用UI自動化測試啓動它時,從控件的樹中消失。我們試圖啓動這樣的應用程序:
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自動化樹),但Inspect.exe - 不是。
另外我們的建議是,窗口使用某種緩存是錯誤的 - 在UI自動化客戶端緩存,我們必須明確打開,但我們不這樣做。
因此,說一個簡單的雙擊啓動應用程序會導致控件在樹中,但是Process.Start啓動不會呢? – chrismead
是的,它是正確的。但我們嘗試了3種方式從代碼啓動應用程序 - 沒有人讓我們找到正確的解決方案... – stukselbax
您是否嘗試從cmd窗口啓動應用程序?如果可行,那麼使用ProcessStartInfo.UseShellExecute標誌可能會起作用。 – chrismead