3

I'm trying to build an app that displays in a Pivot informations about several products such as their pictures. Each PivotItem is concerning one product and contains (between other controls) another Pivot where I load the pictures of the product in code behind.

Here's the XAML part :

<Page
x:Class="Inventaire.Fenetres.FicheProduit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Inventaire"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.Resources>
        <ResourceDictionary>

            <DataTemplate x:Key="ProductPivotItem">
                <Grid x:Name="rootGrid" Loaded="rootGrid_Loaded">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>

                    <TextBlock x:Name="productName" Text="{Binding article.name}" FontSize="18" 
                               FontWeight="Bold" HorizontalAlignment="Center" TextWrapping="Wrap"
                               Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"/>

                    <Pivot x:Name="picturesPivot" HorizontalAlignment="Center" Margin="0,5,0,5"
                           VerticalContentAlignment="Top" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>

                    <!-- 

                    Some other controls

                    -->
                </Grid>
            </DataTemplate>

        </ResourceDictionary>
    </Page.Resources>

    <Pivot x:Name="productPivot" ItemsSource="{Binding}"
           ItemTemplate="{StaticResource ProductPivotItem}" />

</Page>

For the moment I load images in the rootGrid_Loaded event, using VisualTreeHelper to get picturesPivot with a method i found there.

Here's the C# extracts :

private void rootGrid_Loaded(object sender, RoutedEventArgs e)
{
    Grid rootGrid = (Grid)sender;

    // FindArticle is a method I wrote to get the product (of class Article) concerned by 
    // the productPivotItem, according to me irrelevant for my problem
    Article art = FindArticle(rootGrid);

    Pivot picturesPivot = (Pivot)FindChildControl<Pivot>(rootGrid, "picturesPivot");
    loadImage(picturesPivot, art);
}

private async void loadImage(Pivot picturesPivot, Article article)
{
    for (int i = 0 ; i < article.images.Count ; i++)
    {
        // ImageProduit is the class gathering infomations I need to build the picture url
        // the images property of the Article class is the collection of ImageProduit for the product
        // and I use AppelWebService (pattern singleton) to get the image from web
        ImageProduit picture = article.images[i];
        BitmapImage bmpImage = await AppelWebService.getInstance().loadImage(picture.ToString());

        Image img = new Image();
        img.Source = bmpImage;

        PivotItem pi = new PivotItem();
        pi.Content = img;
        picturesPivot.Items.Add(pi);
    }
}

private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
{
    DependencyObject result = null;
    bool done = false;
    int i = 0;
    int childNumber = VisualTreeHelper.GetChildrenCount(control);

    while (i < childNumber && !done)
    {
        DependencyObject child = VisualTreeHelper.GetChild(control, i);
        FrameworkElement fe = child as FrameworkElement;

        if (fe == null)
        {
            done = true;
        }
        else if (child is T && fe.Name == ctrlName)
        {
            result = child;
            done = true;
        }
        else
        {
            DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
            if (nextLevel != null)
            {
                result = nextLevel;
                done = true;
            }
        }

        i++;
    }

    return result;
}

I modified a bit the FindChildControl method in order to have only one return at the end of the method. Wrote like this I have no problems loading images.

But, sliding on many products, i discover that after around 70 productPivotItem loaded my emulator crash for OutOfMemoryException. So I want to try to clear picturesPivot.Items when leaving the corresponding productPivotItem to see if it solve the memory problem. For this I thought use the PivotItemLoaded and PivotItemUnloaded events on productPivot, load images on load and clear the picturesPivot items collection on unload.

Unfortunately I am not able to get back the picturesPivot in these event methods.

Here's what I tried :

private void productPivot_PivotItemLoaded(Pivot sender, PivotItemEventArgs args)
{
    // Next three lines independently
    args.Item.UpdateLayout();
    sender.UpdateLayout();
    UpdateLayout();

    Pivot picturesPivot = (Pivot)FindChildControl<Pivot>(args.Item, "picturesPivot");
}

Debuging step by step I saw that args.Item has one child, a Grid without name that has himself one child, a ContentPresenter. This ContentPresenter has no child and I can't get any of my controls defined in the DataTemplate.

How could I find them ? I really need you as I had tearing out on this for too long. I hope I was clear enough, the Pivot Inside Pivot thing can be confusing.

Community
  • 1
  • 1
Krij
  • 31
  • 2

0 Answers0