wpf - No se puede establecer el foco a un hijo de UserControl
focus user-controls (18)
- Establezca su control de usuario en Enfoque = "Verdadero" (XAML)
- Maneje el evento GotFocus en su control y llame a suTextBox.Focus ()
- Maneje el evento cargado en su ventana y llame a suControl.Focus ()
Tengo una aplicación de muestra ejecutándose con esta solución mientras escribo. Si esto no funciona para usted, debe haber algo específico para su aplicación o entorno que cause el problema. En su pregunta original, creo que el enlace está causando el problema. Espero que esto ayude.
Tengo un UserControl
que contiene un TextBox
. Cuando se carga mi ventana principal, quiero establecer el foco en este cuadro de texto, así que agregué Focusable="True" GotFocus="UC_GotFocus"
a la definición de UserControl
y FocusManager.FocusedElement="{Binding ElementName=login}"
a la definición de mi ventana principal . En el método UC_GotFocus
simplemente llamo .Focus()
al control en el que quiero enfocar pero esto no funciona.
Todo lo que necesito hacer es tener un TextBox
en un foco de recepción de UserControl
cuando se inicia la aplicación.
Cualquier ayuda será apreciada, gracias.
"Al establecer el foco inicial al inicio de la aplicación, el elemento para recibir el enfoque debe estar conectado a un PresentationSource y el elemento debe tener Focusable e IsVisible en verdadero. El lugar recomendado para establecer el foco inicial es en el controlador de eventos Loaded "(MSDN)
Simplemente agregue un manejador de eventos "Cargado" en el constructor de su Ventana (o Control), y en ese evento, el manejador llama al método Focus () en el control objetivo.
public MyWindow() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
}
void MyWindow_Loaded(object sender, RoutedEventArgs e) {
textBox.Focus();
}
Convertí la respuesta de fuzquat a un método de extensión. Estoy usando esto en lugar de Focus () donde Focus () no funcionó.
using System;
using System.Threading;
using System.Windows;
namespace YourProject.Extensions
{
public static class UIElementExtension
{
public static void WaitAndFocus(this UIElement element, int ms = 100)
{
ThreadPool.QueueUserWorkItem(f =>
{
Thread.Sleep(ms);
element.Dispatcher.Invoke(new Action(() =>
{
element.Focus();
}));
});
}
}
}
Después de probar combinaciones de las sugerencias anteriores, pude asignar de manera confiable el foco al cuadro de texto deseado en un UserControl secundario con lo siguiente. Básicamente, concéntrese en el control del niño y pida al niño UserControl que enfoque su TextBox. La declaración de enfoque de TextBox devolvió verdadera por sí misma, sin embargo, no produjo el resultado deseado hasta que también se le dio el foco al UserControl. También debo señalar que el UserControl no pudo solicitar el foco por sí mismo y tuvo que ser dado por la ventana.
Para abreviar, dejé de registrar los eventos cargados en la ventana y UserControl.
Ventana
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
ControlXYZ.Focus();
}
Control de usuario
private void OnControlLoaded(object sender, RoutedEventArgs e)
{
TextBoxXYZ.Focus();
}
Después de tener un ''WPF Initial Focus Nightmare'' y basado en algunas respuestas en la pila, lo siguiente me resultó ser la mejor solución.
Primero, agregue su App.xaml OnStartup () los siguientes:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
new RoutedEventHandler(WindowLoaded));
A continuación, agregue el evento ''WindowLoaded'' también en App.xaml:
void WindowLoaded(object sender, RoutedEventArgs e)
{
var window = e.Source as Window;
System.Threading.Thread.Sleep(100);
window.Dispatcher.Invoke(
new Action(() =>
{
window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}));
}
El problema de enhebrado debe ser utilizado ya que el enfoque inicial de WPF falla principalmente debido a algunas condiciones de carrera de infraestructura.
Encontré la siguiente solución mejor, ya que se usa globalmente para toda la aplicación.
Espero eso ayude...
Orán
El truco para mí fue el atributo FocusManager.FocusedElement . Primero intenté configurarlo en UserControl, pero no funcionó.
Así que traté de ponerlo en el primer hijo del UserControl:
<UserControl x:Class="WpfApplication3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
<TextBox x:Name="MyTextBox"/>
</Grid>
... ¡Y funcionó! :)
Encontré una buena serie de publicaciones de blog sobre el enfoque de WPF.
- Parte 1: Básicamente se enfoca
- Parte 2: Cambiar el foco de WPF en el código
- Parte 3: Cambio de enfoque al primer elemento disponible en WPF
Todos son buenos para leer, pero la tercera parte trata específicamente de establecer el foco en un elemento de UI en un UserControl.
Es estúpido pero funciona:
Pop un hilo que espera un rato luego vuelve y establece el foco que desea. Incluso funciona dentro del contexto de un elemento host.
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(
(a) =>
{
System.Threading.Thread.Sleep(100);
someUiElementThatWantsFocus.Dispatcher.Invoke(
new Action(() =>
{
someUiElementThatWantsFocus.Focus();
}));
}
);
}
Hace poco resolví este problema para una pantalla de inicio de sesión que se muestra a través de un guión gráfico cuando se carga por primera vez la ventana principal.
Creo que había dos claves para la solución. Una era hacer que el elemento contenedor fuera un ámbito de enfoque. El otro fue para manejar el evento Storyboard Completed para el guión gráfico que fue activado por la ventana que se está cargando.
Este guión gráfico hace visible el lienzo de nombre de usuario y contraseña y luego se desvanece para ser 100% opaco. La clave es que el control de nombre de usuario no estaba visible hasta que se ejecutó el guión gráfico y, por lo tanto, ese control no pudo enfocar el teclado hasta que estuvo visible. Lo que me desanimó por un tiempo fue que tenía "foco" (es decir, el enfoque era cierto, pero resultó ser solo un enfoque lógico) y no sabía que WPF tenía el concepto de enfoque tanto lógico como de teclado hasta leer el de Kent Boogaart. responder y mirar el texto de enlace de WPF de Microsoft
Una vez que hice eso, la solución para mi problema particular fue sencilla:
1) Hacer que el elemento contenedor sea un ámbito de enfoque
<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
<TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
</TextBox>
</Canvas>
2) Adjunte un controlador de eventos completado al guión gráfico
<Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>
y
3) Establecer mi nombre de usuario TextBox para que el teclado se enfoque en el manejador de eventos completo del guión gráfico.
void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
m_uxUsername.Focus();
}
Tenga en cuenta que llamar al elemento. Focus () da como resultado la llamada Keyboard.Focus (this), por lo que no necesita llamar esto explícitamente. Consulte esta pregunta sobre la diferencia entre Teclado. Enfoque (elemento) y elemento. Enfoque.
Hace poco tuve un list box que contenía algunos TextBlocks. Quería poder hacer doble clic en el bloque de texto y hacer que se convierta en un cuadro de texto, luego centrarme en él y seleccionar todo el texto para que el usuario pueda comenzar a escribir el nuevo nombre (similar a las capas de Adobe)
De todos modos, estaba haciendo esto con un evento y simplemente no estaba funcionando. La bala mágica para mí aquí fue asegurarme de que configuré el evento para que lo manejara. Me imagino que estaba enfocando, pero tan pronto como el evento pasó por el camino, estaba cambiando el enfoque lógico.
La moraleja de la historia es, asegúrese de marcar el evento como manejado, ese podría ser su problema.
He notado un problema de enfoque específicamente relacionado con el alojamiento de WPF UserControls dentro de ElementHosts que están contenidos dentro de un Formulario que se establece como un MDI secundario a través de la propiedad MdiParent.
No estoy seguro de si este es el mismo problema que otros están experimentando, pero profundiza en los detalles siguiendo el siguiente enlace.
Lo configuro en PageLoaded () o control cargado, pero luego llamo al servicio asincrónico WCF y hago cosas que parecen perder el foco. Tengo que establecerlo al final de todas las cosas que hago. Eso está bien y todo, pero a veces hago cambios en el código y luego me olvido de que también estoy colocando el cursor.
No me gustan las soluciones con la configuración de otro alcance de pestaña para UserControl. En ese caso, tendrá dos carátulas diferentes cuando navegue con el teclado: en la ventana y el otro, dentro del control del usuario. Mi solución es simplemente redirigir el foco del control del usuario al control interno del niño. Establecer el control del usuario enfocable (porque por defecto es falso):
<UserControl ..... Focusable="True">
y anula los controladores de eventos de foco en código subyacente:
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
MyTextBox.Focus();
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
Keyboard.Focus(MyTextBox);
}
Suponiendo que desea establecer el foco para el cuadro de texto del nombre de usuario, el usuario puede escribir directamente cada vez que aparece.
En Constructor de tu control:
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
Tengo control de usuario: apilar panel con dos cuadros de texto. Los cuadros de texto se agregaron en contructor, no en xaml. Cuando trato de enfocar el primer cuadro de texto, no pasa nada. La señalización con el evento Loaded soluciona mi problema. Recién llamado control.Enfoque () en evento cargado y todo.
Tuve el mismo problema al configurar el foco del teclado en el control de usuario de WPF. Mi solución
- En elemento de conjunto XAML a
Focusable="True"
En el evento
element_mousemove
crea una verificación simple:if(!element.IsKeyBoardFocused) element.Focus();
En mi caso, funciona bien.
WPF admite dos tipos diferentes de foco:
- Enfoque del teclado
- Enfoque lógico
La propiedad FocusedElement
obtiene o establece el enfoque lógico dentro de un ámbito de enfoque. Sospecho que su TextBox
tiene un enfoque lógico, pero su alcance de enfoque no es el alcance de enfoque activo. Ergo, no tiene foco en el teclado.
Entonces, la pregunta es, ¿tiene múltiples ámbitos de enfoque en su árbol visual?
desde que probé la solución de fuzquat y la encontré la más genérica, pensé que compartiría una versión diferente, ya que algunos se quejaron de que se veía desordenada. asi que aqui esta:
casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
{
x.Focus();
}), DispatcherPriority.ApplicationIdle, casted);
no Thread. Sleep, no ThreadPool. Lo suficientemente limpio, espero. Realmente podría usar algún representante para poder comentar sobre las soluciones de otras personas.
ACTUALIZAR:
Como a la gente parece gustarle el código bonito:
public static class WpfExtensions
{
public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
{
element.Dispatcher.BeginInvoke(priority, action);
}
}
ahora puedes llamarlo así:
child.BeginInvoke(d => d.Focus());