xleon
xleon

Reputation: 6365

When is a XAML (UWP) GridView completely loaded?

<GridView 
    Name="Slider"
    ItemsSource="{Binding Node.Contents}"
    Loaded="SliderLoaded"
    .../>

The ViewModel initialization is async and that´s where I set the Node property referenced in the binding.

This is the style for the items panel:

<Setter Property="ItemsPanel">
    <Setter.Value>
        <ItemsPanelTemplate>
            <ItemsStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </Setter.Value>
</Setter>

On code behind:

private async void SliderLoaded(object sender, RoutedEventArgs e)
{
    // I get a null reference exception trying to access the GridView scrollViewer here

    await Task.Delay(150); // [hack] wait a bit for the view tree and binding to be ready

    // the scrollViewer is accessible after the delay
}

And this how I access the ScrollViewer:

public static ScrollViewer GetScrollViewer(this DependencyObject element)
{
    if (element is ScrollViewer)
    {
        return (ScrollViewer)element;
    }

    for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
    {
        var child = VisualTreeHelper.GetChild(element, i);

        var result = GetScrollViewer(child);
        if (result != null)
            return result;
    }

    return null;
}

Reading docs and other SO answers, the "loaded" event handler seams like the place where all sub-views and bindings are created and available, but as you can see in the comments, it´s not working.

I also tried DataContextChanged event handler with the same result.

How or when can I be 100% sure the grid scrollViewer and items are in place?

Upvotes: 0

Views: 755

Answers (2)

xleon
xleon

Reputation: 6365

Sorry for the confusion. My code was working and I didn´t realize. Thing is that I had a function getting the ScrollView and other stuff to find items and do an animated scrolling. The ScrollView was there but other parts in the code wrapped in a TaskCompletionSource were failing silently.

Anyway, the whole point of all of this was to programmatically scroll the GridView, and all the problems were gone when I replaced the ItemsStackPanel with a StackPanel in the ItemsPanelTemplate.

Sorry to bother and thank you all.

Upvotes: 0

Decade Moon
Decade Moon

Reputation: 34286

You didn't specify how you are getting the GridView's ScrollViewer. I'm assuming you're using VisualTreeHelper to do so?

This works for me:

<GridView Loaded="GridView_Loaded"/>
private void GridView_Loaded(object sender, RoutedEventArgs e)
{
    var scrollViewer = ((UIElement)sender)
                           .ChildrenBreadthFirst()
                           .OfType<ScrollViewer>()
                           .First();
}
public static class Extensions
{
    public static IEnumerable<UIElement> ChildrenBreadthFirst(this UIElement element)
    {
        var queue = new Queue<UIElement>();
        queue.Enqueue(element);

        while (queue.Count > 0)
        {
            element = queue.Dequeue();
            var count = VisualTreeHelper.GetChildrenCount(element);

            for (var i = 0; i < count; i++)
            {
                var child = (UIElement)VisualTreeHelper.GetChild(element, i);
                yield return child;
                queue.Enqueue(child);
            }
        }
    }
}

Upvotes: 1

Related Questions