我希望用户按姓名或员工编号搜索员工。然后我提供了一个文本框。因此,当用户在文本框中键入时,我处理 _TextChanged 事件并使用员工列表更新 dataGridview,其中员工姓名或员工编号包含用户在文本框中输入的文本。
遇到的问题是这会减慢输入速度和 datagridview 更新,因为每次文本框中的文本更改时,我的搜索查询都会命中数据库。这使得表单有些反应迟钝。
有人知道更好的方法吗?
我在下面的演示代码中想到了类似的东西:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication19
{
public partial class Form1 : Form
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
public Form1()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
// cancel old query and datagrid update
tokenSource.Cancel();
tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task.Factory.StartNew((s) =>
{
var q = Task.Factory.StartNew<IEnumerable<DemoData>>(() => LongLastingDataQuery(textBox1.Text, token), token);
if (!token.IsCancellationRequested)
Task.Factory.StartNew(() => BindData(q.Result));
}, token);
}
private IEnumerable<DemoData> LongLastingDataQuery(string search, CancellationToken token)
{
List<DemoData> l = new List<DemoData>();
for (int i = 0; i < 10000 * search.Length; i++)
{
if (token.IsCancellationRequested)
return l;
l.Add(new DemoData { ID = i, Text = search + i, Text1 = search + i + i, Text2 = search + i + i + i, Text3 = search + i + i + i + i });
}
Thread.Sleep(1000);
return l;
}
private void BindData(IEnumerable<DemoData> enumerable)
{
if (dataGridView1.InvokeRequired)
dataGridView1.Invoke(new MethodInvoker(() => BindData(enumerable)));
else
{
demoDataBindingSource.DataSource = null;
demoDataBindingSource.DataSource = enumerable;
}
}
public class DemoData
{
public string Text { get; set; }
public string Text1 { get; set; }
public string Text2 { get; set; }
public string Text3 { get; set; }
public int ID { get; set; }
}
}
}
我有两个建议给你:
处理“TextBox enter KeyPressdown”事件而不是TextChange事件,因此该事件仅在您键入查询后按下“Return”键时触发。示例代码是这样的:
private void searchTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Return)
{
// DoQueryAndRebindEmployees(searchTextBox.Text);
}
}
如果您坚持在 TextChange 事件中处理,请将数据库搜索代码放在另一个线程中,例如在 BackgroundWorker 线程中,在 TextChange 事件处理程序中:
BackgroundWorker employeeQueryWorker = new BackgroundWorker();
employeeQueryWorker.DoWork += new DoWorkEventHandler(employeeQueryWorker_DoWork);
employeeQueryWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(employeeQueryWorker_RunWorkerCompleted);
employeeQueryWorker.RunWorkerAsync(searchTextBox.Text);
Backgroundwork线程和UI线程之间的通信,可以定义一个类的成员变量来表示员工查询结果,比如
private IList<Employee> m_employeeQueryResult = null;
然后在employeeQueryWorker_DoWork(object sender, DoWorkEventArgs e) 线程方法中,执行耗时的数据库查询并将查询结果存储到 m_employeeQueryResult 中。
最后,在employeeQueryWorker_RunWorkerCompleted() 方法中,将m_employeeQueryResult 与DataGridView 控件绑定。
这将使 UI 控件保持响应。