ContentControl não é visível quando o aplicativo é iniciado por meio do teste de Automação da Interface do Usuário, mas é visível quando o aplicativo é iniciado pelo usuário
Estamos usando o prisma e o WPF para criar aplicativos. Recentemente, começamos a usar a UI Automation (UIA) para testar nosso aplicativo. Mas algum comportamento estranho ocorreu quando corremos o teste UIA. Aqui está o shell simplificado:
<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>
Em nosso aplicativo, usamos camadas (Popup
eErrorPopup
) esconderMainViewArea, para negar acesso aos controles. MostrarPopup
, usamos o próximo método:
//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 a isso, mostramosErrorPopup
sobre todos os elementos da nossa aplicação:
// 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);
}
}
Mística ...
Quando executamos isso como os usuários fazem (clique duas vezes no ícone do aplicativo), podemos ver ambos os controles personalizados (usandoAutomationElement.FindFirst
método, ou através deAutomação de interface do usuário visual). Mas quando começamos usando o teste de Automação da Interface do Usuário -ErrorPopup
desaparece da árvore dos controles. Estamos tentando iniciar o aplicativo assim:
System.Diagnostics.Process.Start(pathToExeFile);
Eu acho que perdemos alguma coisa. Mas o que?
Editar # 1
Como disse @chrismead, tentamos executar nosso aplicativo comUseShellExecute
flag definido como true, mas isso não ajuda. Mas se começarmos o aplicativo decmd linha e clique manualmente no botão,Popup
eErrorPopup
são visíveis na árvore de controles de automação.
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();
Uma de nossas sugestões é quando usamos o métodoFindAll
ouFindFirst
para pesquisar o botão para clicar, janela de alguma forma armazenada em cache seu estado de automação da interface do usuário e não atualizá-lo.
Editar # 2 Nós encontramos, esse método de extensão da biblioteca de prismasIRegionManager.RegisterViewWithRegion(RegionNames.OurRegion, typeof(Views.OurView))
tem algum comportamento estranho. Se paramos de usá-lo, isso resolve nosso problema particularmente. Agora podemos ver ErrorView e qualquer tipo de visualização emPopupContentControl
e aplicativo atualiza a estrutura da árvore de elementos UIA. Mas isso não é uma resposta - "Basta parar de usar esse recurso"!
EmMainViewArea
nós temos umaContentControl
, que atualiza o conteúdo de acordo com as ações do usuário, e podemos ver apenas o primeiro carregadoUserControl
para issoContentControl.Content
propriedade. Isso é feito assim:
IRegionManager regionManager = Container.Resolve<IRegionManager>();
regionManager.RequestNavigate(RegionNames.MainContentRegion, this.Uri);
E se alterarmos a exibição, nenhuma atualização será executada na árvore de Automação da Interface do Usuário - a primeira exibição carregada estará nela. Mas visualmente observamos outraView
eWPFInspector mostra-lo corretamente (seu show não uma árvore de automação de interface do usuário), mas Inspect.exe - não.
Além disso, nossa sugestão de que a janela use algum tipo de armazenamento em cache está errada - o armazenamento em cache no cliente de Automação da Interface do Usuário precisa ser ativado explicitamente, mas não o fazemos.