Windows 10 UWP - 不可见时没有 DataContext 的 GridView 项目

Posted

技术标签:

【中文标题】Windows 10 UWP - 不可见时没有 DataContext 的 GridView 项目【英文标题】:Windows 10 UWP - GridView Items With no DataContext when Not Visible 【发布时间】:2016-08-16 18:17:23 【问题描述】:

我正在处理的 UWP 应用程序中的 GridView 存在问题...

GridView 中的项目可以正确加载,但是不在视图中的项目(离开页面且不可见)没有分配 DataContext,并且在分配 DataContext 时不会触发任何事件。各种绑定确实可以作为绑定的 TextBlock 进行更新,但正常的事件工作流程和 Loaded 事件变得很奇怪。

<GridView Grid.Row="1" Name="SearchGrid" ItemsSource="Binding SearchItems" ItemClick="SearchGrid_ItemClick">
        <GridView.ItemTemplate>
            <DataTemplate>
                <local:RsrItemGridViewItem />
            </DataTemplate>
        </GridView.ItemTemplate>
    </GridView>

网格都正确显示,除了能够正确延迟加载某些项目,因为在加载时未设置 DataContext(并且更新上下文时未触发 DataContextChanged 事件)。

有没有人知道如何在控件可见时获得通知?这似乎是一个通知错误,或者我缺少一些绑定的东西。

谢谢!

【问题讨论】:

【参考方案1】:

有没有人知道如何在控件可见时获得通知?

当您的RsrItemGridViewItem 变为可见时,您不能在此处使用FrameworkElement.Loaded event 来获得通知,此事件在FrameworkElement 已构建并添加到对象树并准备好进行交互时发生。

GirdView 控件实现UI virtualization 以获得更好的UI 性能,如果您的GridView 绑定到许多项目的集合,它可能只下载项目1-50,当用户滚动到列表末尾附近时,然后下载项目 51 – 100,依此类推。但是例如,现在只显示了 20 个项目,但它可能已经加载了 45 个项目,此时无法看到 25 个项目。

如果您将GridView 的默认ItemsPanel (即ItemsWrapGrid)更改为例如VariableSizedWrapGridGridView 将失去虚拟化,所有项目将同时加载,即使大多数项目无法加载在一瞬间被看到。

对于您的问题,我认为您可以尝试使用您的GridView 的高度计算ScrollViewer 的VerticalOffset 并显示项目的计数,然后您可以知道哪些项目显示在这一刻。

例如这里:

private ObservableCollection<MyList> list = new ObservableCollection<MyList>();

public MainPage()

    this.InitializeComponent();
    this.Loaded += MainPage_Loaded;


private double viewheight;

private void MainPage_Loaded(object sender, RoutedEventArgs e)

    var scrollViewer = FindChildOfType<ScrollViewer>(gridView);
    scrollViewer.ViewChanged += ScrollViewer_ViewChanged;
    viewheight = gridView.ActualHeight;


private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)

    var scrollViewer = sender as ScrollViewer;
    var Y = scrollViewer.VerticalOffset;
    //calculate here to get the displayed items.


public static T FindChildOfType<T>(DependencyObject root) where T : class

    var queue = new Queue<DependencyObject>();
    queue.Enqueue(root);
    while (queue.Count > 0)
    
        DependencyObject current = queue.Dequeue();
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(current); i++)
        
            var child = VisualTreeHelper.GetChild(current, i);
            var typedChild = child as T;
            if (typedChild != null)
            
                return typedChild;
            
            queue.Enqueue(child);
        
    
    return null;


protected override void OnNavigatedTo(NavigationEventArgs e)

    list.Clear();
    for (int i = 0; i < 200; i++)
    
        list.Add(new MyList  text = "Item " + i );
    

由于GridView控件的布局是自适应app的大小,当前显示的计数是动态的,你可以尝试其他基于高度的属性(例如每个项目的高度)和ScrollViewer的VerticalOffset来计算,有没有现成的方法来完成你的工作,计算起来有点复杂,但我认为目前没有更好的解决方案。

【讨论】:

在对此进行了一些测试后,我发现有效(虽然它不是很干净,而且我相信绑定存在错误)是将自定义控件添加到 GridView,然后在网格视图将DataContext=Binding 添加到我想要收到更新通知的图像中。 &lt;Image DataContext="Binding" DataContextChanged="ItemImage_DataContextChanged" /&gt; 主控件不会收到 DataContext 更改的通知,但会通知子元素。 @Josh,问题是,即使它有一个DataContext,并不意味着那个项目在那一刻可以被看到。 是的......但我认为真正的问题是,当孩子们收到 DataContextChanged 通知时,绑定到同一上下文的父母没有收到这些通知。在我上面的示例中,RsrItemGridViewItem 的子项收到 DataContextChanged 通知,但主 RsrItemGridViewItem 没有收到通知。 @Josh,DataContextChanged 具有路由行为,但不是真正的路由事件(它没有 RoutedEvent 标识符)。此外,它从父级路由到子级,而真正的路由事件从子级路由到父级。可以参考FrameworkElement.DataContextChanged event。这不是一个错误,它只是被设计成这样。【参考方案2】:

在对此进行一些测试之后,我发现有效(虽然它不是很干净,而且我相信绑定存在错误)是将自定义控件添加到 GridView,然后在网格视图中添加一个 @ 987654321@ 发送到我想收到更新通知的图片。

<UserControl ...><Image DataContext="Binding" DataContextChanged="ItemImage_DataContextChanged" /></UserControl>

主控件不会收到 DataContext 更改的通知,但会通知子元素。

【讨论】:

以上是关于Windows 10 UWP - 不可见时没有 DataContext 的 GridView 项目的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C# 从 Windows 10 日历中检索 UWP 中的约会

UWP StoreProductQueryResult不返回任何产品

在Windows 10 C#UWP通用Windows应用程序中获取UserName

2019-11-29-win10-uwp-如何判断一个控件在滚动条的里面是用户可见

在页面调整大小之前,UWP图像有时不可见

如何在 Windows 10 上的 UWP 中输出到控制台?