Xamarin.Forms — ListView с панелью поиска зависает в пользовательском интерфейсе

У меня есть ListView и SearchBar, я использую событие TextChanged SearchBar для фильтрации результатов ListView. Однако каждый раз, когда я ввожу значение в SearchBar, пользовательский интерфейс зависает.

Вот видео с реальным поведением, которое я вижу:

https://drive.google.com/open?id=1SM94AbD_00WDQT9yzpJN8ta_NDj4Lb13

1.- Я не вызываю веб-службу в событии TextChanged, а фильтрую предварительно загруженный список в памяти. Функция возвращает отфильтрованный список всего за миллисекунды.

2.- ListView использует GroupHeaderTemplate.

3.- В списке около 150 строк.

Как я могу предотвратить зависание пользовательского интерфейса?

Вот код:

// TextChanged Event

void Handle_TextChanged(object sender, Xamarin.Forms.TextChangedEventArgs e)
{

           Xamarin.Forms.Device.BeginInvokeOnMainThread(() => {

                this.lsProducts.BeginRefresh();

                this.lsProducts.ItemsSource = App.Locator.Products.FilterProducts(e.NewTextValue);

                this.lsProducts.EndRefresh();
           });

}




 // FilterProducts VM function
public List<products_list> FilterProducts(string filter)
{
    List<products_list> theCollection = new List<products_list>();

    if ( ! string.IsNullOrEmpty( filter ) )
    {
        if (_products_list != null)
        {

            List<products_list> entities = (                        
                                            from e in _products_list
                                            where e.Any( x => x.search_field_text.Contains( filter.ToLowerInvariant() ) )
                                            select e
                                           ).ToList<products_list>();



            // if there's entities
            if (entities != null && entities.Any())
            {

                entities.ForEach(x => theCollection.Add(
                    new products_list( 
                            x.products
                            .Where(y => y.search_field_text.Contains( filter.ToLowerInvariant() ) )
                            .ToList() 
                        )
                        {
                            header = x.header
                        }
                    )
                );


            }

        }
    }
    else
    {
        theCollection = _products_list;
    }

    return theCollection;
}

Я могу поделиться более подробной информацией, дайте мне знать.


person Luis de Haro    schedule 03.07.2018    source источник
comment
Ваша проблема, скорее всего, связана с рендерингом Listview. Насколько сложен ваш пользовательский интерфейс? Вы используете CachingStrategy?   -  person Bruno Caceiro    schedule 03.07.2018


Ответы (1)


Ваш пользовательский интерфейс зависает из-за вашего запроса LINQ, написанного внутри функции события TextChanged. Вы можете уменьшить количество зависаний пользовательского интерфейса, оптимизировав запрос LINQ.

var searReqs = yourlist.Where(p => (!String.IsNullOrEmpty(p.Attribute1) && p.Attribute1.ToLower().Contains(searchString.ToLower()))

В приведенном выше коде соответствующие атрибуты для поиска уже предварительно загружены, что означает, что вам не нужно снова выполнять SELECT из списка, и вы можете напрямую применить предложение WHERE. (это предложение было протестировано для 450 строк с полем поиска)

Позвольте мне указать на некоторые проблемы с вашим кодом. Предположим, что ваш набор "entities" возвращает 100 элементов, предполагается, что эта задача выполняется относительно быстро. Но цикл foreach, который вы написали, будет проблемой, потому что он должен пройти 100 раз вместе с предложением WHERE в LINQ. Эта задача определенно замедлит работу пользовательского интерфейса.

Я дал ссылку на оптимизацию запроса LINQ. Посмотри на это.

Использованная литература:

Должен ли порядок предложений запроса LINQ влиять на Entity Framework производительность?

https://www.codeproject.com/Articles/38174/How-to-improve-your-LINQ-query-performance-by-X

https://codereview.stackexchange.com/questions/41273/reduce-or-improve-linq-query-with-nested-from-where-clauses

Весь поисковый код приведен ниже для вашей мысли.

public void searchData(String serString)
    {
        var searReqs = refList_PettyCash.Where(p => (!String.IsNullOrEmpty(p.Amount) && p.Amount.ToLower().Contains(serString.ToLower()))
                                                          || (!String.IsNullOrEmpty(p.CurApproverFullName) && p.CurApproverFullName.ToLower().Contains(serString.ToLower()))
                                                          || (!String.IsNullOrEmpty(p.CategoryDescription) && p.CategoryDescription.ToLower().Contains(serString.ToLower()))
                                                          || (!String.IsNullOrEmpty(p.Note) && p.Note.ToLower().Contains(serString.ToLower()))
                                                          || (!String.IsNullOrEmpty(p.RequestCode) && p.RequestCode.ToLower().Contains(serString.ToLower()))
                                                          || (!String.IsNullOrEmpty(p.RequestedOn) && p.RequestedOn.ToLower().Contains(serString.ToLower()))
                                                          || (!String.IsNullOrEmpty(p.StatusDesc) && p.StatusDesc.ToLower().Contains(serString.ToLower()))
                                                          || (!String.IsNullOrEmpty(p.Vendor) && p.Vendor.ToLower().Contains(serString.ToLower())))
                                                             .OrderByDescending(p => p.RequestCode)
                                                            .ToList();
        PettyCashRequests = new ObservableRangeCollection<PettyCashRequestsModel>(searReqs);
    }
person Selvarathinam Vinoch    schedule 03.07.2018
comment
Я удалил ForEach из кода, и пользовательский интерфейс по-прежнему зависает (однако производительность немного улучшилась, спасибо!) cs" rel="nofollow noreferrer">gist.githubusercontent.com/LuisDeHaro/ - person Luis de Haro; 05.07.2018