Estamos utilizando el prisma y WPF para crear la aplicación. Recientemente comenzamos a usar la UI Automation (UIA) para probar nuestra aplicación. Pero algún comportamiento extraño ocurrió cuando ejecutamos la prueba UIA. Aquí está la cáscara simplificado:ContentControl no está visible cuando la aplicación se inicia a través de la prueba de automatización de UI, pero es visible cuando la aplicación se inicia por el usuario
<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>
En nuestra aplicación, usamos capas (Popup
y ErrorPopup
) para ocultar MainViewArea, para negar el acceso a los controles. Para mostrar Popup
, utilizamos el método siguiente:
//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 esto, mostramos ErrorPopup
sobre todos los elementos de nuestra aplicación:
// 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ístics ...
Cuando corremos como lo hacen los usuarios (haga doble clic en el ícono de la aplicación), podemos ver ambos controles personalizados (usando el método AutomationElement.FindFirst
, o a través del Visual UI Automation Verify). Pero cuando lo comenzamos usando la prueba de automatización UI - ErrorPopup
desaparece del árbol de los controles. Estamos tratando de iniciar la aplicación de esta manera:
System.Diagnostics.Process.Start(pathToExeFile);
Creo que nos hemos perdido algo. ¿Pero que?
Edición # 1
Como dijo @chrismead, tratamos de ejecutar nuestra aplicación con UseShellExecute
indicador se define como true, pero esto no soluciona el problema. Pero si iniciamos la aplicación desde la línea cmd y hacemos clic manualmente en el botón, Popup
y ErrorPopup
están visibles en el árbol de controles de automatización.
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();
Una de nuestra sugerencia es cuando usamos el método FindAll
o FindFirst
para buscar el botón para hacer clic, la ventana de algún modo en caché su estado de UI Automation, y no lo actualiza.
Edición # 2 Hemos de encontrar, que el método de extensión de la biblioteca prisma IRegionManager.RegisterViewWithRegion(RegionNames.OurRegion, typeof(Views.OurView))
tienen un comportamiento extraño. Si dejamos de usarlo, esto resolverá nuestro problema en particular. Ahora podemos ver ErrorView y cualquier tipo de vista en PopupContentControl
, y la aplicación actualiza la estructura del árbol de los elementos UIA. Pero esta no es una respuesta: "¡Solo deja de usar esta característica"!
En MainViewArea
tenemos una ContentControl
, que actualiza su contenido en función de las acciones del usuario, y que son capaces de ver sólo la primera carga UserControl
a que ContentControl.Content
propiedad. Esto se realiza así:
IRegionManager regionManager = Container.Resolve<IRegionManager>();
regionManager.RequestNavigate(RegionNames.MainContentRegion, this.Uri);
Y si cambiamos el punto de vista, no hay actualizaciones se realizan en el árbol de UI Automation - la primera vista cargada estará en su lugar. Pero visualmente observamos otro View
, y WPFInspector lo muestra correctamente (su show no es un árbol de Automatización de UI), pero Inspect.exe - no.
también nuestra sugerencia de que la ventana use algún tipo de almacenamiento en caché está mal - el almacenamiento en caché en el cliente de UI Automation tenemos que activar de forma explícita, pero no lo hacemos.
lo tanto, es correcto decir que un simple doble clic lanzamiento de los resultados de la aplicación en el control está en el árbol, pero el lanzamiento de un Process.Start no lo hace? – chrismead
Sí, es correcto. Pero probamos 3 maneras de iniciar la aplicación desde el código: nadie nos lleva a la solución correcta ... – stukselbax
¿Has probado a ejecutar la aplicación desde una ventana de cmd? Si eso funciona, entonces podría funcionar el uso del indicador ProcessStartInfo.UseShellExecute. – chrismead