Xamarin.Forms-具有SearchBar的ListView冻结UI

时间:2018-07-03 14:45:09

标签: listview xamarin.forms searchbar

我有一个ListView和一个SearchBar,我使用SearchBar的TextChanged事件来过滤ListView的结果。但是,每次我在SearchBar上输入一个值时,UI都会冻结。

这是一个具有我所看到的实际行为的视频:

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

1.-我没有在TextChanged事件中调用Web服务,而是在内存中过滤了预加载的列表。该函数仅需毫秒即可返回过滤后的列表。

2。-ListView使用GroupHeaderTemplate。

3.-列表大约有150行。

如何防止UI冻结?

代码如下:

// 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 :(得分:0)

由于在TextChanged事件函数中编写了LINQ查询,因此UI冻结。您可以通过优化LINQ查询来减少UI冻结。

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

在上面的代码中,搜索的相关属性已经预先加载,这意味着您不必再次从列表中执行SELECT,并且可以直接应用WHERE子句。 (此子句已针对包含搜索字段的450行进行了测试)

让我指出一些有关您的代码的问题。 假设您的“ 实体”集返回100个项目,并且此任务相对较快。但是您编写的“ foreach ”循环将成为问题,因为它必须与LINQ中的WHERE子句一起循环100次。该任务肯定会减慢用户界面的速度。

我提供了一些参考来优化LINQ查询。看看吧。

参考文献:

Should the order of LINQ query clauses affect Entity Framework performance?

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);
    }