Xamarin.Forms - ListView с SearchBar замораживает пользовательский интерфейс - PullRequest
0 голосов
/ 03 июля 2018

У меня есть 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;
}

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

1 Ответ

0 голосов
/ 03 июля 2018

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

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

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

Позвольте мне указать на некоторые проблемы, связанные с вашим кодом. Предположим, что ваш набор " entity " возвращает 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);
    }
...