Ленивая загрузка невидимых элементов - PullRequest
3 голосов
/ 08 апреля 2011

У меня есть случай, когда у меня есть элемент управления gridview / listbox / любого типа, а количество элементов, связанных с элементом управления, огромно (легко около 5000+).

Каждый из этих элементов должен иметь различные атрибуты, загружаемые из различных веб-сервисов.Очевидно, что об обращении к веб-службам для одновременной обработки такого количества элементов не может быть и речи.

Мой вопрос: возможно ли отложить загрузку до тех пор, пока эти элементы фактически не отобразятся пользователю?Например, пользователь прокручивает вниз, и хотя элементы все время присутствуют в коллекции, они обрабатываются только тогда, когда они фактически визуализируются физически.

Я видел, как это было сделано ранее, но не могупомни где именно.Это была ситуация, когда большое количество биржевых котировок находилось в коллекции, привязанной к сетке, но их атрибуты (цены и т. Д.) Оставались пустыми, пока они не отображались в первый раз (путем прокрутки до соответствующей позиции).

Надеюсь, это имело (какой-то) смысл.

Есть идеи, как это осуществить?

Ответы [ 2 ]

1 голос
/ 08 апреля 2011

Я бы попробовал комбинацию ленивой загрузки и асинхронной загрузки:
Используйте виртуальный список управления. Создайте ViewModel для ваших элементов и заполните свой список экземплярами ViewModel (по одному на строку).

В вашей ViewModel создайте свойства со значением по умолчанию, которое показывает пользователю, что данные не были загружены. При первом обращении к одному из этих свойств запускается загрузка данных асинхронно и запускается INotifyPropertyChanged при получении реальных данных.

Это даст пользователю хороший опыт, и большая часть хитрой работы будет выполнена через список виртуализации (в WPF это ListBox, ListView, DataGrid ...). Надеюсь, это помогло.

class LineItemVM : INotifyPropertyChanged{

  bool   m_loadingTriggered;
  string m_name="Loading...";
  string m_anotherProperty="Loading...";


  public string Name{
     get{
       TriggerLoadIfNecessary(); // Checks if data must be loaded
       return m_name;
     }
  }

  public string AnotherProperty{
     get{
       TriggerLoadIfNecessary(); // Checks if data must be loaded
       return m_anotherProperty;
     }
  }


  void TriggerLoadIfNecessary(){        
     if(!m_loadingTriggered){
       m_loadingTriggered=true;

       // This block will called before your item will be displayed
       //  Due to the m_loadingTriggered-member it is called only once.
       // Start here the asynchronous loading of the data
       // In virtualizing lists, this block is only called if the item
       //  will be visible to the user (he scrolls to this item)

       LoadAsync();
     }
  }

  ...

Дополнительная логика В качестве идеи вы могли бы также создать внешний асинхронный поток загрузки, который загружает все данные в фоновом режиме, но имеет список элементов, которые должны быть загружены с более высоким приоритетом. Концепция такая же, как в приведенном выше примере, но вместо загрузки данных из элемента ViewModel метод TriggerLoadIfNecessary добавляет только элемент в список с высоким приоритетом, так что потенциально видимые элементы загружаются первыми. Вопрос о том, какая версия лучше подходит, зависит от использования списка. Если существует вероятность того, что пользователь использует полный список и не будет быстро перемещаться, эта расширенная версия лучше. В противном случае оригинальная версия, вероятно, лучше.

0 голосов
/ 03 августа 2016

Вот событие, которое будет уведомлять, когда пользователь прокручивает последний экран данных:

using System.Windows;
using System.Windows.Controls;

public static class ScrollViewer
{
    public static readonly RoutedEvent LastPageEvent = EventManager.RegisterRoutedEvent(
        "LastPage",
        RoutingStrategy.Bubble,
        typeof(RoutedEventHandler),
        typeof(ScrollViewer));

    private static readonly RoutedEventArgs EventArgs = new RoutedEventArgs(LastPageEvent);

    static ScrollViewer()
    {
        EventManager.RegisterClassHandler(
            typeof(System.Windows.Controls.ScrollViewer),
            System.Windows.Controls.ScrollViewer.ScrollChangedEvent,
            new ScrollChangedEventHandler(OnScrollChanged));
    }
    public static void AddLastPageHandler(UIElement e, RoutedEventHandler handler)
    {
        e.AddHandler(LastPageEvent, handler);
    }

    public static void RemoveLastPageHandler(UIElement e, RoutedEventHandler handler)
    {
        e.RemoveHandler(LastPageEvent, handler);
    }

    private static void OnScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (e.ViewportHeight == 0 || e.VerticalOffset == 0)
        {
            return;
        }

        var verticalSpaceLeft = e.ExtentHeight - e.VerticalOffset;
        if (verticalSpaceLeft < 2 * e.ViewportHeight)
        {
            var scrollViewer = (System.Windows.Controls.ScrollViewer)sender;
            scrollViewer.RaiseEvent(EventArgs);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...