2008-11-30 6 views
9

Ich habe DataTemplate enthält eine TextBox. Ich setze diese Vorlage auf einen Listeneintrag in einer Auswahl.Konzentrieren Sie sich auf eine TextBox in einem DataTemplate

Ich kann nicht den Fokus auf Textfeld in der Vorlage festlegen. Ich habe versucht, MyTemplate.FindName aufzurufen, aber es endet mit einer ungültigen Vorgangsausnahme: Diese Operation ist nur für Elemente gültig, auf die diese Vorlage angewendet wurde.

Wie kann ich darauf zugreifen?

Antwort

9

Da Sie den Namen der TextBox kennen, die Sie fokussieren möchten, wird dies relativ einfach. Die Idee ist, die Vorlage zu erhalten, wie sie auf die ListBoxItem selbst angewendet wird.

Der erste, was Sie tun möchten, ist das ausgewählte Element zu erhalten:

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

Dann können Sie, dass in diese kleine Helfer-Funktion übergeben, die basierend auf dem Namen ein Kontrollpunkt:

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 Erraten Sie, dass das knifflige Bit dafür sorgt, dass Sie darauf warten, dass das Objekt geladen wird. Ich musste diesen Code hinzufügen, weil ich dies vom ItemContainerGenerator.StatusChanged Ereignis anrief und manchmal war die ListBoxItem nicht vollständig initialisiert, als wir die Methode eingaben.

+1

FindResource gibt ein Objekt zurück, also stellen Sie sicher, dass es in ein FrameworkTemplate umgewandelt wird. – Michael

10

Ich weiß, das ist alt, aber ich lief heute über dieses Thema und am Ende kam mit dieser Auflösung bis:

Da die TextBox nur dann geladen wird, wenn ein Element ausgewählt ist, und das ist, wenn Sie wollen Fokus gesetzt werden, können Sie einfach das Ereignis TextBox.Load behandeln und Focus() aufrufen.

Es gibt zwei Möglichkeiten, dies zu erreichen.

1. Ersetzen Sie die TextBox in der DataTemplate durch eine AutoFocusTextBox.

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

Vergessen Sie nicht, dass Sie den Namespace verweisen müssen, in dem AutoFocusTextBox in Ihrem XAML-Datei definiert ist.

2. Fügen Sie einen Handler im Codebehind der Datei hinzu, in dem DataTemplate definiert ist.

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(); 
    } 

Mit beiden Optionen, können Sie immer ein anderes Verhalten im Handler, fügen Sie wie alle Textauswahl .

2

Jays zweiter Vorschlag ist ordentlich - und mehr verallgemeinert durch die Verwendung UIElement werden kann, anstatt TextBox, so dass jede Steuerung leicht den Standard gemacht werden kann:

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

Ok. Also ich denke, ich habe die beste Lösung. Es funktionierte für mich sowieso. Ich habe eine einfache Datenvorlage, in der ich den Fokus auf das Textfeld legen möchte. Die FocusManager Hände weg Fokus auf das Textfeld.

<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

Schön und sauber, funktioniert auch für mich und ich mag es – veljkoz

Verwandte Themen