通过 Tasks C# 动态搜索中断
Dynamically search with interrupts,via Tasks C#
我正在使用 Db(通过 SQLite.NET PCL,不是异步版本)。目前我有一个 listview 和一些数据(从数据库中获取),我也有一个 searchbar/entry(它的 nvm),用户可以在其中输入一些值,然后通过LINQ 我将进行查询并更新我的列表的 SourceItems。
所以问题来自性能,因为我的 DB 有百万条记录和简单的 LINQ 查询非常 slow.In 其他换句话说,当用户输入某些数据时速度过快,应用程序会出现巨大的滞后,有时会 崩溃 。
为了解决这个问题,我想到了一些事情(理论上的解决方案):
1)需要将方法(我查询数据库)放在任务上(以解锁我的主 UI 线程)
2)初始化定时器,然后打开并:
- 如果 1 秒过去了,则 => 运行 我在任务上的方法(查询)(类似于后台线程)
- 如果1秒未通过,则退出匿名方法。
类似的东西(相似)或任何 suggestions.Thanks!
UPD:
所以老实说,我尝试了太多并没有得到好的结果
顺便说一句,我当前的代码(片段):
1) 我的搜索方法
public void QueryToDB(string filter)
{
this.BeginRefresh ();
if (string.IsNullOrWhiteSpace (filter))
{
this.ItemsSource = SourceData.Select(x => x.name); // Source data is my default List of items
}
else
{
var t = App.DB_Instance.FilterWords<Words>(filter); //FilterWords it's a method,where i make direct requests to the database
this.ItemsSource = t.Select(x => x.name);
}
this.EndRefresh ();
}
2)Searchbar.TextChanged(匿名方法)
searchBar.TextChanged +=async (sender, e) =>
{
ViewModel.isBusy = true; //also i got a indicator,to show progress,while query working
await Task.Run(()=> //my background,works fine
{
listview.QueryToDB(searchBar.Text);
});
ViewModel.isBusy = false; // after method is finished,indicator turn off
};
主要问题是如何实现这部分(在这些情况下),其中 1 秒过去了,然后我才进行查询以更新我的 sourceItems[=列表的 53=](每次,当用户在搜索栏中输入一些值时,此触发器(计时器)必须再次刷新为零)。
任何帮助将不胜感激,谢谢!
PS 对不起我的工程师。技能!
您想等待,然后再实际执行搜索。中途终止搜索任务会导致未定义的行为。
您想保存当前的搜索筛选条件,并在 1 秒后再次比较。如果没有改变,请进行搜索。否则,中止:
searchBar.TextChanged += async (sender, e) =>
{
var filter = searchBar.Text;
await Task.Run(() =>
{
Thread.Sleep(1000);
if (filter == searchBar.Text)
listview.QueryToDB(searchBar.Text);
});
};
为了保持视图模型更新,请将您的 isBusy
作业移至 QueryToDB
内,因为那是您的视图模型真正忙碌的时候:
public void QueryToDB(string filter)
{
this.BeginRefresh ();
ViewModel.isBusy = true;
// do your search
ViewModel.isBusy = false;
this.EndRefresh ();
}
一种方法是结合 async Task.Run
和 CancellationTokenSource
:
CancellationTokenSource cancellationTokenSource;
searchView.TextChanged += async (sender, e) =>
{
if (cancellationTokenSource != null) cancellationTokenSource.Cancel();
cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var searchBar = (sender as SearchBar);
if (searchBar != null)
{
string searchText = searchBar.Text;
try
{
await Task.Delay(650, cancellationToken);
if (cancellationToken.IsCancellationRequested) return;
var searchResults = await Task.Run(() =>
{
return ViewModel.Search(searchText);
});
if (cancellationToken.IsCancellationRequested) return;
ViewModel.YouItems.Repopulate(searchResults);
}
catch (OperationCanceledException)
{
// Expected
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
};
我正在使用 Db(通过 SQLite.NET PCL,不是异步版本)。目前我有一个 listview 和一些数据(从数据库中获取),我也有一个 searchbar/entry(它的 nvm),用户可以在其中输入一些值,然后通过LINQ 我将进行查询并更新我的列表的 SourceItems。
所以问题来自性能,因为我的 DB 有百万条记录和简单的 LINQ 查询非常 slow.In 其他换句话说,当用户输入某些数据时速度过快,应用程序会出现巨大的滞后,有时会 崩溃 。
为了解决这个问题,我想到了一些事情(理论上的解决方案):
1)需要将方法(我查询数据库)放在任务上(以解锁我的主 UI 线程)
2)初始化定时器,然后打开并:
- 如果 1 秒过去了,则 => 运行 我在任务上的方法(查询)(类似于后台线程)
- 如果1秒未通过,则退出匿名方法。
类似的东西(相似)或任何 suggestions.Thanks!
UPD:
所以老实说,我尝试了太多并没有得到好的结果
顺便说一句,我当前的代码(片段):
1) 我的搜索方法
public void QueryToDB(string filter)
{
this.BeginRefresh ();
if (string.IsNullOrWhiteSpace (filter))
{
this.ItemsSource = SourceData.Select(x => x.name); // Source data is my default List of items
}
else
{
var t = App.DB_Instance.FilterWords<Words>(filter); //FilterWords it's a method,where i make direct requests to the database
this.ItemsSource = t.Select(x => x.name);
}
this.EndRefresh ();
}
2)Searchbar.TextChanged(匿名方法)
searchBar.TextChanged +=async (sender, e) =>
{
ViewModel.isBusy = true; //also i got a indicator,to show progress,while query working
await Task.Run(()=> //my background,works fine
{
listview.QueryToDB(searchBar.Text);
});
ViewModel.isBusy = false; // after method is finished,indicator turn off
};
主要问题是如何实现这部分(在这些情况下),其中 1 秒过去了,然后我才进行查询以更新我的 sourceItems[=列表的 53=](每次,当用户在搜索栏中输入一些值时,此触发器(计时器)必须再次刷新为零)。
任何帮助将不胜感激,谢谢!
PS 对不起我的工程师。技能!
您想等待,然后再实际执行搜索。中途终止搜索任务会导致未定义的行为。
您想保存当前的搜索筛选条件,并在 1 秒后再次比较。如果没有改变,请进行搜索。否则,中止:
searchBar.TextChanged += async (sender, e) =>
{
var filter = searchBar.Text;
await Task.Run(() =>
{
Thread.Sleep(1000);
if (filter == searchBar.Text)
listview.QueryToDB(searchBar.Text);
});
};
为了保持视图模型更新,请将您的 isBusy
作业移至 QueryToDB
内,因为那是您的视图模型真正忙碌的时候:
public void QueryToDB(string filter)
{
this.BeginRefresh ();
ViewModel.isBusy = true;
// do your search
ViewModel.isBusy = false;
this.EndRefresh ();
}
一种方法是结合 async Task.Run
和 CancellationTokenSource
:
CancellationTokenSource cancellationTokenSource;
searchView.TextChanged += async (sender, e) =>
{
if (cancellationTokenSource != null) cancellationTokenSource.Cancel();
cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var searchBar = (sender as SearchBar);
if (searchBar != null)
{
string searchText = searchBar.Text;
try
{
await Task.Delay(650, cancellationToken);
if (cancellationToken.IsCancellationRequested) return;
var searchResults = await Task.Run(() =>
{
return ViewModel.Search(searchText);
});
if (cancellationToken.IsCancellationRequested) return;
ViewModel.YouItems.Repopulate(searchResults);
}
catch (OperationCanceledException)
{
// Expected
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
};