¿Cómo acceder a un elemento específico en un Listbox con DataTemplate?

Tengo un ListBox que incluye una ItemTemplate con 2 StackPanels. Hay un TextBox en el segundo StackPanel al que quiero acceder. (Cambie su visibilidad a verdadera y acepte la entrada del usuario) El desencadenador debe ser SelectionChangedEvent. Entonces, si un usuario hace clic en un ListBoxItem, el TextBlock se vuelve invisible y el TextBox se vuelve visible.

CÓDIGO XAML:

                          

Supongo que hay varias formas de resolver esto, pero nada de lo que probé funcionó.

Mi enfoque actual se ve así

  private void ContactListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { ListBoxItem listBoxItem = ContactListBox.SelectedItem as ListBoxItem; DataTemplate listBoxTemplate = listBoxItem.ContentTemplate; // How to access the DataTemplate content? StackPanel outerStackPanel = listBoxTemplate.XXX as StackPanel; StackPanel innerStackPanel = outerStackPanel.Children[1] as StackPanel; TextBox nameBox = innerStackPanel.Children[0] as TextBox; TextBlock nameBlock = innerStackPanel.Children[1] as TextBlock; nameBox.Visibility = System.Windows.Visibility.Visible; nameBlock.Visibility = System.Windows.Visibility.Collapsed; } 

¡¡Gracias por su ayuda chicos!! Finalmente lo tengo. Resolvió el problema con VisualTreeHelper. Qué gran función ^^

 private void ContactListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (ContactListBox.SelectedIndex == -1) return; currentSelectedListBoxItem = this.ContactListBox.ItemContainerGenerator.ContainerFromIndex(ContactListBox.SelectedIndex) as ListBoxItem; if (currentSelectedListBoxItem == null) return; // Iterate whole listbox tree and search for this items TextBox nameBox = helperClass.FindDescendant(currentSelectedListBoxItem); TextBlock nameBlock = helperClass.FindDescendant(currentSelectedListBoxItem); 

helperFunction

 public T FindDescendant(DependencyObject obj) where T : DependencyObject { // Check if this object is the specified type if (obj is T) return obj as T; // Check for children int childrenCount = VisualTreeHelper.GetChildrenCount(obj); if (childrenCount < 1) return null; // First check all the children for (int i = 0; i < childrenCount; i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child is T) return child as T; } // Then check the childrens children for (int i = 0; i < childrenCount; i++) { DependencyObject child = FindDescendant(VisualTreeHelper.GetChild(obj, i)); if (child != null && child is T) return child as T; } return null; } 

Con esta función editada también puede buscar el control por nombre (se convierte de VB.NET):

 public T FindDescendantByName(DependencyObject obj, string objname) where T : DependencyObject { string controlneve = ""; Type tyype = obj.GetType(); if (tyype.GetProperty("Name") != null) { PropertyInfo prop = tyype.GetProperty("Name"); controlneve = prop.GetValue((object)obj, null); } else { return null; } if (obj is T && objname.ToString().ToLower() == controlneve.ToString().ToLower()) { return obj as T; } // Check for children int childrenCount = VisualTreeHelper.GetChildrenCount(obj); if (childrenCount < 1) return null; // First check all the children for (int i = 0; i <= childrenCount - 1; i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child is T && objname.ToString().ToLower() == controlneve.ToString().ToLower()) { return child as T; } } // Then check the childrens children for (int i = 0; i <= childrenCount - 1; i++) { string checkobjname = objname; DependencyObject child = FindDescendantByName(VisualTreeHelper.GetChild(obj, i), objname); if (child != null && child is T && objname.ToString().ToLower() == checkobjname.ToString().ToLower()) { return child as T; } } return null; } 

No puedo darte una respuesta completa …

Pero creo que puede usar el VisualTreeHelper para iterar a través de los elementos secundarios de cualquier control http://blogs.msdn.com/b/kmahone/archive/2009/03/29/visualtreehelper.aspx

Sin embargo, para el efecto que está buscando, entonces creo que usar el estilo SelectedItem podría ser una mejor solución. Por ejemplo, vea este artículo: http://joshsmithonwpf.wordpress.com/2007/07/30/customizing-the-selected- item-in-a-listbox /

Dado que DataTemplate es una plantilla genérica que podría usarse muchas veces en el código, no hay forma de acceder a ella por su nombre (x: Name = “numberTextBox”).

Resolví un problema similar al hacer una colección de controles: mientras Listbox se estaba poblando, agregué el control Textbox a la colección.

 string text = myCollectionOfTextBoxes[listbox.SelectedIndex].Text; 

Hasta que encontré una alma mejor – Propiedad de etiqueta. En su ListboxItem enlaza la propiedad Tag al nombre

 Tag="{Binding Name}" 

y el para acceder

 ListBoxItem listBoxItem = ContactListBox.SelectedItem as ListBoxItem; string name = listBoxItem.Tag.ToString(); 

Use ItemContainerGenerator .

 private void ContactListBox_SelectionChanged (object sender, SelectionChangedEventArgs e) { if (e.AddedItems.Count == 1) { var container = (FrameworkElement)ContactListBox.ItemContainerGenerator. ContainerFromItem(e.AddedItems[0]); StackPanel sp = container.FindVisualChild(); TextBox tbName = (TextBox) sp.FindName("tbName"); TextBlock lblName = (TextBlock)sp.FindName("lblName"); TextBlock lblNumber = (TextBlock)sp.FindName("lblNumber"); } }