Windows phone 8 LayoutMode=Grid中LongListSelector的延迟加载

Windows phone 8 LayoutMode=Grid中LongListSelector的延迟加载,windows-phone-8,windows-phone,Windows Phone 8,Windows Phone,我在WP8上的LongListSelector中显示了一组图像,并利用LLS的ItemRealized事件实现了 在下面的代码中,为图片集合中的每一个项目都调用了OnItemRealized,即使是那些明显不在屏幕上的项目也是如此。在这个场景中,屏幕上有24个项目,而LLS实现了40个项目,这将触发ViewModel的ResumeGetPictures()。当图片集合更改(INotifyCollectionChanged)时,LLS也将实现这些项目,直到项目用完,触发下一个ResumeGetPi

我在WP8上的LongListSelector中显示了一组图像,并利用LLS的ItemRealized事件实现了

在下面的代码中,为图片集合中的每一个项目都调用了OnItemRealized,即使是那些明显不在屏幕上的项目也是如此。在这个场景中,屏幕上有24个项目,而LLS实现了40个项目,这将触发ViewModel的ResumeGetPictures()。当图片集合更改(INotifyCollectionChanged)时,LLS也将实现这些项目,直到项目用完,触发下一个ResumeGetPictures()-这将一直持续到ViewModel无法加载更多项目为止

只要LLS处于LayoutMode=List,一切似乎都很好。但当我切换到网格时,控件似乎吞下了列表中的每一项,并立即实现了它。使任何类型的延迟加载都不可能

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

视图模型:

public IReactiveDerivedList<TPicture> Pictures
{
  get { return pictures; }
}
<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:

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

通过观察LLS内的滚动条,我能够获得想要的效果。我已将功能抽象为易于重用的行为:

  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;
      }
    }
  }
公共类LLSIncrementalLoadingBehavior:行为
{
私有滚动条llsScrollBar;
#区域依赖属性
公共静态只读DependencyProperty RequestMoreDataProperty=DependencyProperty.Register(
“RequestMoreData”、typeof(Action)、typeof(LLSIncrementalLoadingBehavior)、newpropertymetadata(null,OnRequestMoreDataChanged));
/// 
///要调用以启动加载更多数据的操作
/// 
公共行动数据
{
获取{返回(操作)this.GetValue(RequestMoreDataProperty);}
set{this.SetValue(RequestMoreDataProperty,value);}
}
RequestMoreDataChanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
(LLSIncrementalLoadingBehavior)d.RequestMoreData=(Action)e.NewValue;
}
公共静态只读DependencyProperty ThresholdProperty=DependencyProperty.Register(
“阈值”、类型(双精度)、类型(LLSIncrementalLoadingBehavior)、新属性元数据(0.8,在保留更改时);
/// 
///一个介于0和1之间的值,用于控制多早请求数据。使用1仅在最后触发它
/// 
公共双阈值
{
获取{return(double)this.GetValue(ThresholdProperty);}
set{this.SetValue(ThresholdProperty,value);}
}
ResholdChanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
(LLSIncrementalLoadingBehavior)d.阈值=(双)e.新值;
}
#端区
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.Loaded+=已加载;
}
已加载专用void(对象发送方,RoutedEventArgs e)
{
llsScrollBar=VisualTreeHelperExtensions.FindFirstElementVisualTree(关联对象);
llsScrollBar.ValueChanged+=onllsScrollbar ValueChanged;
}
private void OnllScrollBarValueChanged(对象发送方,RoutedPropertyChangedEventArgs e)
{
var bottomEdge=(float)(e.NewValue+AssociatedObject.ActualHeight);
var bottom=llsScrollBar.max+AssociatedObject.ActualHeight;
var阈值=底部*阈值;
如果(底边>=阈值)
RequestMoreData();
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
如果(llsScrollBar!=null)
{
llsScrollBar.ValueChanged-=onllsScrollbar ValueChanged;
}
}
}
为了完整起见:

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;
}
public static T findfirstelementvisualtree(DependencyObject parentElement),其中T:DependencyObject
{
if(parentElement!=null)
{
var count=VisualTreeHelper.GetChildrenCount(parentElement);
如果(计数=0)
返回null;
for(int i=0;i
这在很大程度上取决于网格中项目的大小,以及您确定列表中最后一项的方式。您应该在这里发布您的代码和XAML。@ClausJørgensen添加了代码。首先,您的乘法将无效,因为
Count
是一个整数。你也可以用一乘以一。至于你的问题,你是说如果你删除了里面的所有逻辑,
onitmrealized
会被调用40次吗?