プリズムと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
メソッドを使用するか、Visual UI Automation Verifyを使用します)。しかし、UI オートメーション テストを使用して開始するErrorPopup
と、コントロールのツリーから消えます。次のようにアプリケーションを起動しようとしています。
System.Diagnostics.Process.Start(pathToExeFile);
私たちは何かを逃したと思います。しかし、何?
編集#1
@chrismead が言ったように、UseShellExecute
フラグを true に設定してアプリを実行しようとしましたが、これは役に立ちません。しかし、コマンドラインからアプリを起動し、ボタンを手動でクリックする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();
私たちの提案の 1 つは、メソッドを使用するFindAll
かFindFirst
、クリックするボタンを検索するときに、ウィンドウが何らかの方法で UI オートメーションの状態をキャッシュし、それを更新しないことです。
編集#2IRegionManager.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 オートメーション ツリーで更新が実行されなくなります。代わりに、最初に読み込まれたビューが表示されます。しかし、視覚的には別の を観察しView
、WPFInspectorはそれを適切に表示します (その表示は UI オートメーション ツリーではありません) が、Inspect.exe は表示しません。
また、window がある種のキャッシュを使用するという提案も間違っています。UI オートメーション クライアントでのキャッシュは、明示的にオンにする必要がありますが、実行していません。