2013-04-25 24 views
0

我希望用戶按名稱或員工編號搜索員工。我已經提供了一個文本框。因此,當用戶在文本框中鍵入內容時,我處理_TextChanged事件並使用員工姓名或員工編號包含用戶在文本框中輸入的文本的員工列表更新dataGridview。作爲用戶在文本框中鍵入即時搜索功能的最佳方式是什麼

問題在於,這會降低輸入和datagridview更新的速度,因爲每次文本框中的文本更改時,我的搜索查詢都會觸擊數據庫。這使得表格有一定的響應。

有人知道更好的方法嗎?

+2

您應該嘗試將數據庫結果緩存在列表中。然後從列表中取代'_TextChanged'上的數據庫 – gwin003 2013-04-25 12:56:34

+0

我支持此評論 – 2013-04-25 12:59:59

+0

只有在文本框中有一定數量的字符時,才能搜索數據庫,例如3.然後按照gwin003的建議,結果列表中,並且對於字符> 3,從該列表中繪製您的結果。這樣,如果字符退格到<3,它只會運行另一個查詢。 – 2013-04-25 13:02:49

回答

2
  • 簡單:延遲通過記住上次的一些文本已更改查詢半秒或第二,以保證用戶已經停止打字分貝。
  • 長期效果更好:如果數據庫查詢需要很長時間(超過一秒),那麼您可以將查詢數據庫外包給另一個線程(任務或後臺工作)。如果數據量太大,繪圖需要很長時間,您甚至可以在自己的任務中填充DataGrid。你也可以通過 實現一些取消機制,並且你的主要圖形用戶界面 保持響應。

我想到了類似下面的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; } 
     } 
    } 
} 
+0

添加了一些工作演示代碼,以展示如何使用嵌套任務完成此任務。 – wonko79 2013-04-25 14:34:22

0

我對你有兩個建議:

  1. 處理 「文本框中輸入KeyPressdown」 事件而不是TextChange事件,因此只有在鍵入查詢後按下「返回」鍵時纔會觸發事件。示例代碼是這樣的:

    private void searchTextBox_KeyPress(object sender, KeyPressEventArgs e) 
    { 
        if (e.KeyChar == (char)Keys.Return) 
        { 
         // DoQueryAndRebindEmployees(searchTextBox.Text); 
        } 
    } 
    
  2. 如果你堅持在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控制響應。

相關問題