Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Views inside a DataTemplate at runtime in Xamarin.Forms

I would like to know if there is a way to obtain a reference to a view inside a DataTemplate in a ListView in Xamarin.Forms. Supposing I have this xaml:

<ListView x:Name="ProductList" ItemsSource="{Binding Products}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout BackgroundColor="#eee" x:Name="ProductStackLayout"
                                     Orientation="Vertical" Padding="5" Tapped="ListItemTapped">
                            <Label Text="{Binding Name}" 
                                   Style="{DynamicResource ProductPropertiesStyle}"/>
                            <Label Text="{Binding Notes}" IsVisible="{Binding HasNotes}" 
                                    Style="{DynamicResource NotesStyle}"
                                />
                            <Label Text="{Binding Date}" 
                                   Style="{DynamicResource DateStyle}"
                            />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

I would like to be able to grab a reference to the StackLayout named "ProductStackLayout" in every row of the ListView. I need to do this when the page is appearing, to dynamically manipulate it's content (for something than can't be achieved with data binding), so I can't take advantage of view references passed in event handlers originating from elements in the DataTemplate itself like ItemTapped or similar.

For what I know, in WPF or UWP something like that could be achieved with the help of the VisualTreeHelper class, but I don't believe there is an equivalent of this class in Xamarin.Forms.

like image 387
Francesco Blue Avatar asked Mar 19 '18 23:03

Francesco Blue


2 Answers

Yeah, It is possible access the view which is created using DataTemplate in run-time. Hook BindingContextChanged event for the view inside the DataTemplate from XAML. In the event call back, the view created from DataTemplate can be accessed using sender parameter. You need type cast the sender to access the view, because sender is boxed to object type.

Or else, you can go for DataTemplate selector to create views based on your object.

like image 148
Dharmendar Dhanasekar Avatar answered Oct 16 '22 08:10

Dharmendar Dhanasekar


You can also cast like this:

    ITemplatedItemsView<Cell> templatedItemsView = listView as ITemplatedItemsView<Cell>;
    ViewCell firstCell = templatedItemsView.TemplatedItems[0] as ViewCell;
    StackLayout stackLayout = firstCell.View as StackLayout;

Which will give you reference to the views


But you probably want to react based on the change of the binding context since you otherwise will have to manually change the content of the view.

Using BindingContextChanged I suspect would make you render the content twice - first the change causes a render like normal - afterwards you render it again. So if for instance a change in a string occurs - a label will rerender - afterwards you get the value in BindingContextChanged and preform the render that you actually wanted.

You can subclass ListView which i think would prevent it:

public class CustomListView : ListView
{
    protected override void SetupContent(Cell content, int index)
    {
        // render differently depending on content.BindingContext
        base.SetupContent(content, index);
    }
}
like image 21
lolelo Avatar answered Oct 16 '22 07:10

lolelo