简体   繁体   中英

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?

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);
            }
        }
    }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM