【问题标题】:Lazy Loading with LongListSelector in LayoutMode=Grid在 LayoutMode=Grid 中使用 LongListSelector 进行延迟加载
【发布时间】:2013-11-02 19:25:19
【问题描述】:

我在 WP8 上的 LongListSelector 中显示一组图像,并且我已经利用 LLS 的 ItemRealized 事件实现了 well known lazy loading pattern

在下面的代码中,对 Pictures 集合中的每个项目都调用 OnItemRealized - 即使是明显不在屏幕上的项目。在这种情况下,屏幕上适合 24 个项目,但 LLS 实现了 40 个项目,这会触发 ViewModel 的 ResumeGetPictures()。当 Pictures 集合发生变化 (INotifyCollectionChanged) 时,LLS 也会意识到这些项目,直到它用完项目,触发下一个 ResumeGetPictures() - 这将一直持续到 ViewModel 无法加载更多项目。

只要 LLS 处于 LayoutMode=List 中,一切似乎都很好。但是当我切换到 Grid 时,控件似乎会吞下列表中的每一项并立即意识到这一点。使任何类型的延迟加载成为不可能。

我希望我只是做了一些非常非常错误的事情-尽管我对此表示怀疑,因为我已经对所有内容进行了三次检查,并且就像我说的那样切换到“列表”可以立即解决问题-不幸的是,这不是某种照片库的选项.

视图模型:

public IReactiveDerivedList<TPicture> Pictures
{
  get { return pictures; }
}

查看代码隐藏

lls.ItemRealized += OnItemRealized;

private void OnItemRealized(object sender, ItemRealizationEventArgs e)
{
  var picture = e.Container.Content as Picture;

  if (picture != null)
  {
    // get index
    var pictureIndex = lls.ItemsSource.IndexOf(picture);

    if (pictureIndex >= lls.ItemsSource.Count * 0.95f)
      ViewModel.ResumeGetPictures();
  }
}

XAML:

<phone:LongListSelector Name="lls" Margin="13,-30,0,0"
  ItemsSource="{Binding Pictures}"
  Tap="OnListItemTapped"
  ItemTemplate="{StaticResource ItemTemplate}"           
  IsGroupingEnabled="False"
  LayoutMode="Grid" 
  GridCellSize="108,108"/>

【问题讨论】:

  • 这在很大程度上取决于网格中项目的大小,以及确定列表中最后一个项目的方式。您应该在此处发布您的代码和 XAML。
  • @ClausJørgensen 代码已添加。
  • 嗯,首先,你的乘法不会有任何效果,因为Count 是一个整数。你还不如乘以一。至于您的问题,您是说 OnItemRealized 被调用 40 次,如果您删除其中的所有逻辑?

标签: windows-phone-8 windows-phone


【解决方案1】:

通过观察 LLS 内的 ScrollBar,我能够得到想要的效果。我已将功能抽象为一种易于重用的行为:

  public class LLSIncrementalLoadingBehavior : Behavior<LongListSelector>
  {
    private ScrollBar llsScrollBar;

    #region Dependency Properties

    public static readonly DependencyProperty RequestMoreDataProperty = DependencyProperty.Register(
      "RequestMoreData", typeof(Action), typeof(LLSIncrementalLoadingBehavior), new PropertyMetadata(null, OnRequestMoreDataChanged));

    /// <summary>
    /// The action to invoke to initiate loading of more data
    /// </summary>
    public Action RequestMoreData
    {
      get { return (Action) this.GetValue(RequestMoreDataProperty); }
      set { this.SetValue(RequestMoreDataProperty, value); }
    }

    private static void OnRequestMoreDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      ((LLSIncrementalLoadingBehavior)d).RequestMoreData = (Action)e.NewValue;
    }

    public static readonly DependencyProperty ThresholdProperty = DependencyProperty.Register(
      "Threshold", typeof(double), typeof(LLSIncrementalLoadingBehavior), new PropertyMetadata(0.8, OnThresholdChanged));

    /// <summary>
    /// A value between 0 and 1 that controls how early more data is requested. Use 1 to only trigger it at the very end
    /// </summary>
    public double Threshold
    {
      get { return (double)this.GetValue(ThresholdProperty); }
      set { this.SetValue(ThresholdProperty, value); }
    }

    private static void OnThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      ((LLSIncrementalLoadingBehavior)d).Threshold = (double)e.NewValue;
    }

    #endregion

    protected override void OnAttached()
    {
      base.OnAttached();
      AssociatedObject.Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
      llsScrollBar = VisualTreeHelperExtensions.FindFirstElementInVisualTree<ScrollBar>(AssociatedObject);

      llsScrollBar.ValueChanged += OnLlsScrollBarValueChanged;
    }

    private void OnLlsScrollBarValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
      var bottomEdge = (float)(e.NewValue + AssociatedObject.ActualHeight);
      var bottom = llsScrollBar.Maximum + AssociatedObject.ActualHeight;
      var threshold = bottom * Threshold;

      if (bottomEdge >= threshold)
        RequestMoreData();
    }

    protected override void OnDetaching()
    {
      base.OnDetaching();

      if (llsScrollBar != null)
      {
        llsScrollBar.ValueChanged -= OnLlsScrollBarValueChanged;
      }
    }
  }

为了完整起见:

public static T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
  if (parentElement != null)
  {
    var count = VisualTreeHelper.GetChildrenCount(parentElement);
    if (count == 0)
      return null;

    for (int i = 0; i < count; i++)
    {
      var child = VisualTreeHelper.GetChild(parentElement, i);

      if (child != null && child is T)
        return (T)child;
      else
      {
        var result = FindFirstElementInVisualTree<T>(child);
        if (result != null)
        {
          return result;
        }
      }
    }
  }
  return null;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 2011-01-09
    • 2017-07-08
    • 2021-07-22
    • 1970-01-01
    相关资源
    最近更新 更多