Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I access a control inside a XAML DataTemplate?

I have this flipview:

<FlipView x:Name="models_list" SelectionChanged="selectionChanged">  <FlipView.ItemTemplate>           <DataTemplate>                 <Grid x:Name="cv">                         <Image x:Name="img1" Source = "{Binding ModelImage}" Stretch="Fill" Tag="{Binding ModelTag}"/>                 </Grid>            </DataTemplate>   </FlipView.ItemTemplate> 

I want to find img1 of currently selected index. While searching for it I found this method on some post here:

private DependencyObject FindChildControl<T>(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<T>(child, ctrlName);                 if (nextLevel != null)                     return nextLevel;             }         }         return null;     } 

It returns me the Image on the first index of flipview but I need the one present on the currently selected index.. I tried to edit this method but I am unable to find the required control. Can anyone help me?

like image 429
Tehreem Avatar asked May 04 '13 14:05

Tehreem


People also ask

How can I access a control in WPF from another class or window?

Access of the controls from within the same assembly is hence allowed. If you want to access a control on a wpf form from another assembly you have to use the modifier attribute x:FieldModifier="public" or use the method proposed by Jean.

Where is Datatemplate control in WPF?

ListBoxItemPhaseListBoxObj = (ListBoxItem)(PhaseListBox… ContainerFromIndex(0)); ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(PhaseListBoxObj);

How can I find WPF controls by name?

FindName method of FrameworkElement class is used to find elements or controls by their Name properties.

What is Datatemplate in XAML?

Data template is a bit of XAML that describes how bound data is displayed. A data template can contain elements that are each bound to a data property along with additional markup that describes layout, color and other appearance.


2 Answers

The problem you are experiencing is that the DataTemplate is repeating and the content is being generated by the FlipView. The Name is not exposed because it would conflict with the previous sibling that was generated (or the next one that will be).

So, to get a named element in the DataTemplate you have to first get the generated item, and then search inside that generated item for the element you want. Remember, the Logical Tree in XAML is how you access things by name. Generated items are not in the Logical Tree. Instead, they are in the Visual Tree (all controls are in the Visual Tree). That means it is in the Visual Tree you must search for the control you want to reference. The VisualTreeHelper lets you do this.

Now, how to do it?

I wrote an article on this because it is such a recurring question: http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html but the meat of the solution is a recursive method that looks something like this:

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<TextBox>()             // 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<Control> AllChildren(DependencyObject parent) {     var _List = new List<Control>();     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; } 

The key issue here is that a method like this gets all the children, and then in the resulting list of child controls you can search for the specific control you want. Make sense?

And now to answer your question!

Because you specifically want the currently selected item, you can simply update the code like this:

if (MyFlipView.SelectedItem == null)     return; var _Container = MyFlipView.ItemContainerGenerator     .ContainerFromItem(MyFlipView.SelectedItem); // then the same as above... 
like image 111
Jerry Nixon Avatar answered Oct 03 '22 04:10

Jerry Nixon


maybe a little more generic approach might be something like this:

private List<Control> AllChildren(DependencyObject parent) {     var _List = new List<Control>();     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<T> (DependencyObject parentContainer, string controlName) {                     var childControls = AllChildren(parentContainer);         var control = childControls.OfType<Control>().Where(x => x.Name.Equals(controlName)).Cast<T>().First();                    return control; } 

You would invoke FindControl like this:

var parentContainer = this.flipView.ItemContainerGenerator.ContainerFromItem(this.flipView.SelectedItem); var myImage = FindControl<Image>(parentContainer, "img1");  //suppose you want to change the visibility myImage.Visibility = Windows.UI.Xaml.Visibility.Collapsed;          
like image 38
user1466108 Avatar answered Oct 03 '22 03:10

user1466108