Do budowy aplikacji używamy pryzmatu i WPF. Niedawno zaczęliśmy używać UI (Automation UI) do testowania naszej aplikacji. Jednak podczas uruchamiania testu UIA pojawiło się dziwne zachowanie. Oto uproszczony shell:ContentControl nie jest widoczny, gdy aplikacja uruchamia się za pomocą testu automatyzacji interfejsu użytkownika, ale jest widoczna po uruchomieniu aplikacji przez użytkownika
<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>
W naszej aplikacji, używamy warstwy (Popup
i ErrorPopup
), aby ukryć MainViewArea, aby zablokować dostęp do elementów sterujących. Aby pokazać Popup
używamy kolejną metodę:
//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;
}
}
podobne do tego, pokażemy ErrorPopup
nad wszystkimi elementami naszej aplikacji:
// 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 ...
Kiedy prowadzimy w miarę jak użytkownicy to robią (dwukrotne kliknięcie ikony aplikacji), widzimy zarówno niestandardowe formanty (używając metody AutomationElement.FindFirst
, jak i przez Visual UI Automation Verify). Ale gdy uruchomimy go, test automatyczny interfejsu użytkownika - ErrorPopup
znika z drzewa elementów sterujących. Próbujemy uruchomić aplikację w następujący sposób:
System.Diagnostics.Process.Start(pathToExeFile);
Myślę, że coś przeoczyliśmy. Ale co?
Edit # 1
Jak @chrismead powiedział, staraliśmy się uruchomić naszą aplikację z UseShellExecute
flaga ustawiona na true, ale to nie pomaga. Ale jeśli uruchomimy aplikację z linii cmd, i ręcznie kliknij przycisk, Popup
i ErrorPopup
są widoczne w drzewie kontroli automatyzacji.
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();
Jeden z naszych sugestii jest, gdy używamy metody FindAll
lub FindFirst
szukać przycisk do kliknięcia, okno jakoś buforowane swój stan UI Automation, a nie aktualizuje go.
Edit # 2 Mamy dowiedzieć, że metoda rozszerzenie pryzmatu biblioteki IRegionManager.RegisterViewWithRegion(RegionNames.OurRegion, typeof(Views.OurView))
jakieś dziwne zachowanie. Jeśli przestaniemy z niego korzystać, rozwiąże to nasz szczególny problem. Teraz możemy zobaczyć ErrorView i dowolny widok w PopupContentControl
, a także zaktualizować strukturę elementów aplikacji UIA. Ale to nie jest odpowiedź - "Po prostu przestań korzystać z tej funkcji"!
W MainViewArea
mamy ContentControl
, która aktualizuje zawartość w zależności od działań użytkownika, a my jesteśmy w stanie zobaczyć tylko pierwszy załadowane UserControl
tej ContentControl.Content
nieruchomości. Odbywa się to tak:
IRegionManager regionManager = Container.Resolve<IRegionManager>();
regionManager.RequestNavigate(RegionNames.MainContentRegion, this.Uri);
A jeśli zmienić widok, żadne aktualizacje będą przeprowadzane w UI Automation drzewa - pierwszy załadowany widok będzie w nim zamiast. Wizualnie obserwujemy jednak, że inny View
i WPFInspector pokazuje go poprawnie (nie pokazuje drzewa automatyzacji interfejsu użytkownika), ale Inspect.exe - nie.
Również nasza sugestia, że okno używa jakiegoś buforowania jest złe - buforowanie w kliencie automatyzacji interfejsu użytkownika musimy włączyć jawnie, ale nie robimy tego.
Czy to słuszne stwierdzenie, że uruchomienie aplikacji z podwójnym kliknięciem powoduje, że kontrolka znajduje się w drzewie, ale proces Process.Start nie działa? – chrismead
Tak, jest to poprawne. Ale próbowaliśmy uruchomić 3 aplikację z kodu - nikt nie jest w stanie nam pomóc w odpowiednim rozwiązaniu ... – stukselbax
Czy próbowałeś uruchomić aplikację z okna cmd? Jeśli to działa, użycie flagi ProcessStartInfo.UseShellExecute może działać. – chrismead