2008-11-30 17 views
9

Tengo DataTemplate que contiene un TextBox. Estoy configurando esta plantilla a un elemento de la lista en una selección.Enfoque en un cuadro de texto en un DataTemplate

No puedo establecer el foco en el cuadro de texto en la plantilla. Traté de llamar a MyTemplate.FindName, pero termina con una excepción de operación no válida: esta operación es válida solo en los elementos que tienen aplicada esta plantilla.

¿Cómo puedo acceder?

Respuesta

9

Dado que conoce el nombre TextBox que desea enfocar, esto se vuelve relativamente fácil. La idea es obtener la plantilla tal como se aplica al ListBoxItem.

Lo primero que quiero hacer es conseguir el artículo seleccionado:

var item = listBox1.ItemContainerGenerator.ContainerFromItem(listBox1.SelectedItem) as ListBoxItem; 

entonces puede pasar que en esta pequeña función auxiliar que se centra un control basado en su nombre:

public void FocusItem(ListBoxItem item, string name) 
{ 
    if (!item.IsLoaded) 
    { 
     // wait for the item to load so we can find the control to focus 
     RoutedEventHandler onload = null; 
     onload = delegate 
     { 
      item.Loaded -= onload; 
      FocusItem(item, name); 
     }; 
     item.Loaded += onload; 
     return; 
    } 

    try 
    { 
     var myTemplate = FindResource("MyTemplateKey") as FrameworkTemplate; // or however you get your template right now 

     var ctl = myTemplate.FindName(name, item) as FrameworkElement; 
     ctl.Focus(); 
    } 
    catch 
    { 
     // focus something else if the template/item wasn't found? 
    } 
} 

I Supongo que el truco es asegurarse de que esperas a que se cargue el artículo. Tuve que agregar ese código porque estaba llamando esto desde el evento ItemContainerGenerator.StatusChanged y, a veces, el ListBoxItem no se había inicializado por completo cuando ingresamos el método.

+1

FindResource devuelve un objeto, así que asegúrese de convertirlo a FrameworkTemplate. – Michael

10

Sé que esto es viejo, pero me encontré con este problema hoy en día y al final ocurrió con esta resolución:

Desde el TextBox solamente se carga cuando se selecciona un elemento, y que es cuando se quiere enfoque para establecerse, simplemente puede manejar el evento TextBox.Load y llamar al Focus().

Hay dos formas de lograr esto.

1. Reemplace el TextBox en el DataTemplate con un AutoFocusTextBox.

public class AutoFocusTextBox : TextBox 
{ 
    public AutoFocusTextBox() 
    { 
     Loaded += delegate { Focus(); }; 
    } 
} 

No se olvide que necesitará para hacer referencia al espacio de nombres en el que AutoFocusTextBox se define en el archivo de .xaml.

2. Agregue un controlador en el código detrás del archivo donde se define DataTemplate.

SomeResourceDictionary.xaml

<TextBox Text="{Binding Something, Mode=TwoWay}" Style={StaticResource ... 
     Loaded="FocusTextBoxOnLoad" /> 

SomeResourceDictionary.xaml.cs

private void FocusTextBoxOnLoad(object sender, RoutedEventArgs e) 
    { 
     var textbox = sender as TextBox; 
     if(textbox == null) return; 
     textbox.Focus(); 
    } 

Con cualquiera de las opciones, siempre se puede añadir otro comportamiento en el controlador, tales como seleccionar todo el texto .

2

segunda sugerencia de Jay es limpio - y puede ser más generalizada mediante el uso de UIElement en lugar de TextBox, de manera que ningún tipo de control se puede hacer fácilmente el valor por defecto:

private void FocusControlOnLoad(object sender, RoutedEventArgs e) 
{ 
    var uiElement = sender as UiElement; 
    if(uiElement == null) return; 
    uiElement.Focus(); 
} 
7

Ok. Entonces creo que tengo la mejor solución. Funcionó para mí de todos modos. Tengo una plantilla de datos simple en la que quiero enfocar el cuadro de texto. El FocusManager manos fuera de foco en el cuadro de texto.

<DataTemplate x:Key="MyDataTemplate" DataType="ListBoxItem"> 
    <Grid> 
     <WrapPanel Orientation="Horizontal" FocusManager.FocusedElement="{Binding ElementName=tbText}"> 
      <CheckBox IsChecked="{Binding Path=Completed}" Margin="5" /> 
      <Button Style="{StaticResource ResourceKey=DeleteButtonTemplate}" Margin="5" Click="btnDeleteItem_Click" /> 
      <TextBox Name="tbText" 
        Text="{Binding Path=Text}" 
        Width="200" 
        TextWrapping="Wrap" 
        AcceptsReturn="True" 
        Margin="5" 
        Focusable="True"/> 
      <DatePicker Text="{Binding Path=Date}" Margin="5"/> 
     </WrapPanel> 
    </Grid> 
</DataTemplate> 
+0

Agradable y limpio, funciona para mí también y me gusta – veljkoz

Cuestiones relacionadas