我有一个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;
}
我可以分享更多细节。
答案 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
下面给出的完整搜索代码供您参考。
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);
}