0

ユーザーに名前または従業員番号で従業員を検索してもらいたい。次に、テキストボックスを提供しました。ユーザーがテキスト ボックスに入力すると、_TextChanged イベントを処理し、従業員名または従業員番号にユーザーがテキスト ボックスに入力しているテキストが含まれる従業員のリストで dataGridview を更新します。

問題は、テキストボックス内のテキストが変更されるたびに検索クエリがデータベースにヒットするため、入力とデータグリッドビューの更新が遅くなることです。これにより、フォームが応答しなくなります。

誰かがより良いアプローチを知っていますか?

4

2 に答える 2

2
  • シンプル: db へのクエリを 0.5 秒または 1 秒遅らせることで、テキストが最後に変更された時刻を思い出して、ユーザーが入力を停止したことを確認します。
  • 長期的にはより良い: db クエリに長い時間がかかる (1 秒以上) 場合は、db のクエリを別のスレッド (タスクまたはバックグラウンドワーカー) にアウトソーシングできます。データが多すぎて描画に時間がかかる場合は、独自のタスクで DataGrid を埋めることもできます。また、いくつかのキャンセル メカニズムを実装することができ、メインの GUI 要素の応答性を維持できます。

以下のデモコードのようなことを考えました:

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; }
        }
    }
}
于 2013-04-25T13:09:44.377 に答える
0

2 つの提案があります。

  1. TextChange イベントの代わりに "TextBox enter KeyPressdown" イベントを処理して、クエリを入力した後に "Return" キーが押されたときにのみイベントがトリガーされるようにします。サンプルコードは次のようになります。

    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);
    

バックグラウンドワーク スレッドと UI スレッドの間で通信するには、クラスのメンバー変数を定義して、次のように従業員のクエリ結果を表すことができます。

 private IList<Employee>  m_employeeQueryResult = null;

次に、employeeQueryWorker_DoWork(object sender, DoWorkEventArgs e) スレッド メソッドで、時間のかかるデータベース クエリを実行し、クエリ結果を m_employeeQueryResult に格納します。

最後に、employeeQueryWorker_RunWorkerCompleted() メソッドで、m_employeeQueryResult を DataGridView コントロールにバインドします。

これにより、UI コントロールの応答性が維持されます。

于 2013-04-25T14:01:00.113 に答える