当用户在文本框中输入时,提供即时搜索功能的最佳方式是什么?
本文关键字:功能 搜索 最佳 是什么 方式 文本 用户 输入 | 更新日期: 2023-09-27 18:11:03
我希望用户通过姓名或员工编号搜索员工。我提供了一个文本框。因此,当用户在文本框中输入时,我处理_TextChanged事件并使用员工列表更新dataGridview,其中员工名称或员工编号包含用户在文本框中输入的文本。
我遇到的问题是,这减慢了输入和datagridview更新,因为每次文本框中的文本变化,我的搜索查询命中数据库。这使得表单在某种程度上缺乏响应性。
有人知道更好的方法吗?
- Simple:延迟查询db半秒或一秒,以确保用户已经停止输入,记住一些文本的最后一次更改。
- 长期更好:如果db查询需要很长时间(超过一秒),那么您可以将查询db外包给另一个线程(任务或后台工作线程)。你甚至可以填满DataGrid在自己的Task中,如果数据太多,需要很长时间来绘制。你也可以实现一些取消机制,你就有了你的主GUI元素保持响应。
我想到了下面的democode:
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);
为了在后台线程和UI线程之间通信,您可以定义类的成员变量来表示员工查询结果,如
private IList<Employee> m_employeeQueryResult = null;
然后在employeeQueryWorker_DoWork(object sender, DoWorkEventArgs e)线程方法中,执行耗时的数据库查询,并将查询结果存储到m_employeeQueryResult中。
最后,在employeeQueryWorker_RunWorkerCompleted()方法中,将m_employeeQueryResult与DataGridView控件绑定。