¿Cómo accedo a un control dentro de XAML DataTemplate?

Tengo este flipview:

        

Quiero encontrar img1 del índice seleccionado actualmente. Mientras lo buscaba encontré este método en alguna publicación aquí:

 private DependencyObject FindChildControl(DependencyObject control, string ctrlName) { int childNumber = VisualTreeHelper.GetChildrenCount(control); for (int i = 0; i < childNumber; i++) { DependencyObject child = VisualTreeHelper.GetChild(control, i); FrameworkElement fe = child as FrameworkElement; // Not a framework element or is null if (fe == null) return null; if (child is T && fe.Name== ctrlName) { // Found the control so return return child; } else { // Not found it - search children DependencyObject nextLevel = FindChildControl(child, ctrlName); if (nextLevel != null) return nextLevel; } } return null; } 

Me devuelve la imagen en el primer índice de Flipview pero necesito la presente en el índice seleccionado actualmente. Intenté editar este método, pero no puedo encontrar el control requerido. ¿Alguien puede ayudarme?

El problema que está experimentando es que DataTemplate se repite y el contenido está siendo generado por FlipView . El Name no está expuesto porque entraría en conflicto con el hermano anterior que se generó (o el próximo que será).

Por lo tanto, para obtener un elemento con nombre en DataTemplate , primero debe obtener el elemento generado y luego buscar dentro del elemento generado para el elemento que desea. Recuerde, el Árbol Lógico en XAML es cómo accede a las cosas por su nombre. Los elementos generados no están en el Árbol lógico. En cambio, están en el árbol visual (todos los controles están en el árbol visual). Eso significa que es en el árbol visual donde debe buscar el control al que desea hacer referencia. El VisualTreeHelper te permite hacer esto.

Ahora, ¿cómo hacerlo?

Escribí un artículo sobre esto porque es una pregunta recurrente: http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html pero la carne de la solución es un método recursivo que se ve así:

 public void TestFirstName() { foreach (var item in MyFlipView.Items) { var _Container = MyFlipView.ItemContainerGenerator .ContainerFromItem(item); var _Children = AllChildren(_Container); var _FirstName = _Children // only interested in TextBoxes .OfType() // only interested in FirstName .First(x => x.Name.Equals("FirstName")); // test & set color _FirstName.Background = (string.IsNullOrWhiteSpace(_FirstName.Text)) ? new SolidColorBrush(Colors.Red) : new SolidColorBrush(Colors.White); } } public List AllChildren(DependencyObject parent) { var _List = new List(); for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var _Child = VisualTreeHelper.GetChild(parent, i); if (_Child is Control) _List.Add(_Child as Control); _List.AddRange(AllChildren(_Child)); } return _List; } 

La cuestión clave aquí es que un método como este obtiene todos los elementos secundarios, y luego en la lista resultante de controles secundarios puede buscar el control específico que desea. ¿Tener sentido?

¡Y ahora para responder tu pregunta!

Como desea específicamente el elemento seleccionado en ese momento, simplemente puede actualizar el código de la siguiente manera:

 if (MyFlipView.SelectedItem == null) return; var _Container = MyFlipView.ItemContainerGenerator .ContainerFromItem(MyFlipView.SelectedItem); // then the same as above... 

tal vez un enfoque un poco más genérico podría ser algo como esto:

 private List AllChildren(DependencyObject parent) { var _List = new List(); for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var _Child = VisualTreeHelper.GetChild(parent, i); if (_Child is Control) { _List.Add(_Child as Control); } _List.AddRange(AllChildren(_Child)); } return _List; } private T FindControl (DependencyObject parentContainer, string controlName) { var childControls = AllChildren(parentContainer); var control = childControls.OfType().Where(x => x.Name.Equals(controlName)).Cast().First(); return control; } 

Invocaría FindControl así:

 var parentContainer = this.flipView.ItemContainerGenerator.ContainerFromItem(this.flipView.SelectedItem); var myImage = FindControl(parentContainer, "img1"); //suppose you want to change the visibility myImage.Visibility = Windows.UI.Xaml.Visibility.Collapsed; 

La solución simple para obtener acceso a los elementos dentro de un DataTemplate es envolver el contenido de DataTemplate en un UserControl, donde se obtiene acceso a todos los elementos de UI en un elemento de ItemsControl. Creo que FlipView generalmente virtualiza sus elementos, por lo que incluso si tienes 100 elementos vinculados a él, solo 2-3 podrían tener una representación actual en la interfaz de usuario (1-2 de ellos ocultos), así que debes recordarlo cuando quieras reemplace cualquier cosa y solo haga cambios cuando se cargue un elemento en el control.

Si realmente necesita identificar un contenedor de artículos que represente el artículo en ItemsSource, puede verificar la propiedad ItemContainerGenerator de FlipView y su método ContainerFromItem () .

Para obtener las coordenadas de un elemento, puede usar el método de extensión GetBoundingRect() en WinRT XAML Toolkit.

En general, sin embargo, en base a su comentario, es posible que el mejor enfoque sea completamente diferente. Si está vinculando su FlipView a una fuente, generalmente puede controlar las imágenes mostradas o superpuestas al cambiar las propiedades de los elementos de la colección fuente asociada.

Si solo desea las coordenadas de la pantalla en el elemento, haga clic en … Puede registrar un controlador de clic en la imagen y luego usar senderimg.transform tovisual (null), esto le da una transición general desde la cual puede obtener las coordenadas del punto actual.

Estuve luchando todo este día, y parece que el control tiene que cargarse (renderizado) para obtener sus controles secundarios de DataTemplate. Esto significa que no puede usar este código o cualquier código (para el mismo propósito) en la ventana cargada, inicializada … Puede usarlo siempre que el control se inicialice, por ejemplo, en SelectedItem.

Sugiero usar conversores y definir la acción solicitada en el convertidor, en lugar del acceso de control directo.

Entonces, si asignó Source vía binding, ¿por qué no haría lo mismo con el rest?

Primero debes preparar el lugar para estas propiedades. Puede ser una clase derivada de INotifyPropertyChanged .

Contrate MVVM para que trabaje para usted, haga más en XAML. Por supuesto, al principio parece ser más trabajo, pero con un proyecto más sofisticado con MVVM será coherente y flexible.