C# 执行任务onTextChanged会冻结用户界面
我的应用程序中有一个文本框和一个列表框。我还有一个有很多玩家的文本文件。我想要的是,每当用户输入一些文本时,查看players文件并将匹配的players添加到匹配列表中,该列表是listbox的数据源。问题是,它看起来非常慢,UI冻结的时间很短,但这很烦人 这是我的代码:C# 执行任务onTextChanged会冻结用户界面,c#,listbox,datasource,freeze,C#,Listbox,Datasource,Freeze,我的应用程序中有一个文本框和一个列表框。我还有一个有很多玩家的文本文件。我想要的是,每当用户输入一些文本时,查看players文件并将匹配的players添加到匹配列表中,该列表是listbox的数据源。问题是,它看起来非常慢,UI冻结的时间很短,但这很烦人 这是我的代码: private void tb_playername_TextChanged(object sender, EventArgs e) { //This method is used to show user the
private void tb_playername_TextChanged(object sender, EventArgs e)
{
//This method is used to show user the options he can choose with the text he has entered
List<string> matching_players = new List<string>();
foreach (var item in all_players)
{
string player = item.f_name + " " + item.l_name;
if ((player.IndexOf(tb_playername.Text, StringComparison.OrdinalIgnoreCase) >= 0))
{
matching_players.Add("(" + item.rating + ") " + item.f_name + " " + item.l_name);
}
}
if (tb_playername.Text.Length >= 4)
{
matching_players.Sort();
matching_players.Reverse()
listbox_matchingplayers.DataSource = matching_players;
}
}
private void tb\u playername\u TextChanged(对象发送方,事件参数e)
{
//此方法用于向用户显示他可以使用输入的文本选择的选项
列表匹配_players=新列表();
foreach(所有玩家的var项目)
{
字符串播放器=item.f_name+“”+item.l_name;
if((player.IndexOf(tb_playername.Text,StringComparison.ordinallingorecase)>=0))
{
匹配玩家。添加(“+item.rating+”)+item.f\u name+“”+item.l\u name);
}
}
如果(tb_playername.Text.Length>=4)
{
匹配玩家。排序();
匹配玩家。反向()
listbox_matchingplayers.DataSource=匹配_玩家;
}
}
问题在于,您正在事件处理程序中执行一项相对耗时的任务。事件处理程序在同一个线程上运行,该线程负责呈现应用程序并处理应用程序的任何其他可视方面,因此,如果该线程很忙,它将无法立即对用户输入做出反应,因此会冻结
解决此问题的标准方法是将耗时的任务卸载到服务器上。后台工作线程将在新线程中操作,从而允许主线程继续处理UI事件。当涉及到使用后台工作程序时,这个示例应该有望使您走上正确的道路
编辑:根据您的问题,您可以只在输入特定数量的字符时开始搜索,例如3,这将减少后台工作人员的运行时间。如果用户继续键入,您可以在运行时停止当前后台工作程序并启动新的后台工作程序
后台工作程序将在完成时触发事件。您可以使用提取返回的列表,然后对其执行操作。问题在于您在事件处理程序中执行的任务相对耗时。事件处理程序在同一个线程上运行,该线程负责呈现应用程序并处理应用程序的任何其他可视方面,因此,如果该线程很忙,它将无法立即对用户输入做出反应,因此会冻结
private async void tb_playername_TextChanged(object sender, EventArgs e)
{
var text = (sender as TextBox).Text;
// Check length of the text
if (string.IsNullOrEmpty(text) || text.Length <= 3)
return;
// Check timer to not process if user still typing, by measuring the key stoke time
...
// Filtering
List<string> matching_players = await PlayerFilter(text);
// Minimize listbox layout time
listbox_matchingplayers.SuspendLayout();
listbox_matchingplayers.DataSource = matching_players;
listbox_matchingplayers.ResumeLayout();
}
//Time consuming method
private async Task<List<string>> PlayerFilter(string text)
{
//This method is used to show user the options he can choose with the text he has entered
return matching_players;
}
解决此问题的标准方法是将耗时的任务卸载到服务器上。后台工作线程将在新线程中操作,从而允许主线程继续处理UI事件。当涉及到使用后台工作程序时,这个示例应该有望使您走上正确的道路
编辑:根据您的问题,您可以只在输入特定数量的字符时开始搜索,例如3,这将减少后台工作人员的运行时间。如果用户继续键入,您可以在运行时停止当前后台工作程序并启动新的后台工作程序
后台工作程序将在完成时触发事件。然后可以使用提取返回的列表并对其进行操作。专用异步void tb\u playername\u TextChanged(对象发送方,事件参数e)
private async void tb_playername_TextChanged(object sender, EventArgs e)
{
var text = (sender as TextBox).Text;
// Check length of the text
if (string.IsNullOrEmpty(text) || text.Length <= 3)
return;
// Check timer to not process if user still typing, by measuring the key stoke time
...
// Filtering
List<string> matching_players = await PlayerFilter(text);
// Minimize listbox layout time
listbox_matchingplayers.SuspendLayout();
listbox_matchingplayers.DataSource = matching_players;
listbox_matchingplayers.ResumeLayout();
}
//Time consuming method
private async Task<List<string>> PlayerFilter(string text)
{
//This method is used to show user the options he can choose with the text he has entered
return matching_players;
}
{
var text=(发送者作为文本框);
//检查文本的长度
if(string.IsNullOrEmpty(text)| | text.Lengthprivate async void tb_playername_TextChanged(对象发送方,事件参数e)
{
var text=(发送者作为文本框);
//检查文本的长度
if(string.IsNullOrEmpty(text)| | text.Length如果用户在BW完成之前输入更多的文本呢?他不能像在后台线程中那样做,因为这些都是他正在使用的UI元素。我通常更喜欢使用异步,等待任务,因为我发现它们写起来更简单:,但当它不比原始问题复杂时,这个答案就足够了。@YuvalItzchakov在后台线程中添加项目后,只需从方法返回列表matching\u players
,然后在UI线程上进行绑定即可。@Aldridge1991:请查看更新答案。我希望这会有所帮助。如果用户在BW完成之前输入更多文本怎么办?他不能像在后台线程中那样执行此操作,因为这些是他正在使用的UI元素。我通常更喜欢使用async,Wait tasks,因为我发现它们更容易编写:,但当它不比原始问题复杂时,这个答案就足够了。@YuvalItzchakov在后台线程中添加项目后,只需从方法返回列表匹配的玩家
,然后执行bindi之后,在UI线程上出现ng。@Aldridge1991:请查看更新答案。我希望这有帮助。