2010-06-24 15 views
8

Mam TextBox z połączeniem zdarzenia TextChanged. W końcu robi zapytanie do bazy danych SQL, więc chcę ograniczyć liczbę zapytań.Jak obsługiwać zdarzenie TextChanged tylko wtedy, gdy użytkownik przestaje pisać?

Chcę tylko wykonać zapytanie , jeśli użytkownik nie nacisnął klawisza w powiedz .. 300 milisekund lub więcej. Jeśli z jakiegoś powodu poprzednia kwerenda wciąż jest wykonywana, musiałbym to anulować, a następnie wydać nowe zapytanie.

Odpowiedz

8

Utwórz System.Windows.Forms.Timer i zresetuj go (na przykład zatrzymaj, a następnie uruchom) po każdym naciśnięciu klawisza. Jeśli zdarzenie czasomierza zostanie wyzwolone, wyłącz licznik czasu.

+0

Jest to metoda, której użyłem i działało idealnie. Zaskakująco nie otrzymuję żadnych wyjątków dotyczących aktualizacji interfejsu przez inny wątek? – esac

+0

Zobacz http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S1. Krótka odpowiedź jest taka, że ​​zdarzenie jest wykonywane w wątku UI. Ma to sens, biorąc pod uwagę, że znajduje się w przestrzeni nazw 'System.Windows.Forms'. – Brian

+0

Należy zauważyć, że łącze do magazynu MSDN powyżej nie jest już linkiem bezpośrednim. Nadal możesz uzyskać do niego dostęp za pomocą [archive.org] (https://web.archive.org/web/20130219050936/http://msdn.microsoft.com/en-us/magazine/cc164015.aspx). Lub po prostu pobierz magazyn z lutego 2004 r. Z tej strony. Jeśli nie masz czytnika CHM, możesz uzyskać dostęp do artykułu, wyodrębniając plik CHM za pomocą 7zip i otwierając '/ MSDNMagazineFebruary2004en-us/TimersinNET/chm.htm' – Brian

0

Dodaj drugą listę akcji, która zostanie wywołana za każdym razem, gdy użytkownik naciśnie dowolny klawisz i gdy zostanie wywołany, zapisz bieżący czas na zmienną globalną. Następnie, gdy wywoływane jest zdarzenie TextChanged, sprawdza różnicę czasu między zmienną globalną i bieżącą.

Jeśli różnica jest mniejsza niż 300 milisekund, należy uruchomić licznik czasu, aby wykonać zapytanie po 300 milisekundach. Następnie, jeśli użytkownik naciśnie inny klawisz, resetuje najpierw zegar.

+0

Wymaga to od użytkownika czekania 300 ms, a następnie wpisania innej litery, jeśli chce przesłać wyniki. – Brian

1

Użyj Reactive Framework, aby uruchomić sekwencję zdarzeń. Nie jestem pewien, czy dokładnie jak to będzie działać, ale możesz przeczytać na ten temat tutaj (Reactive Extensions for .NET) i sprawdzić, czy to będzie spełniało twoje potrzeby. Jest tu także kilka przykładów: Examples. Przykład "Throttling" może być tym, czego szukasz.

0

1) Utwórz licznik czasu.

2) Utwórz procedurę obsługi zdarzenia Tick swojego licznika czasu. Przy każdym tiku sprawdź, czy upłynął wystarczająco dużo czasu bezczynności, a jeśli tak, zatrzymaj timer i wykonaj zapytanie.

3) Za każdym razem, gdy pojawia się naciśnięcie klawisza na tym polu tekstowym, RESTART timera.

1

Dzięki idei @ Briana i this answer, wymyśliłem własną wersję timera do obsługi tego problemu. To działało dobrze dla mnie. Mam nadzieję, że pomoże to także innym:

private Timer _tmrDelaySearch; 
private const int DelayedTextChangedTimeout = 500; 
private void txtSearch_TextChanged(object sender, EventArgs e) 
{ 
    if (_tmrDelaySearch != null) 
    _tmrDelaySearch.Stop(); 

    if (_tmrDelaySearch == null) 
    { 
     _tmrDelaySearch = new Timer(); 
     _tmrDelaySearch.Tick += _tmrDelaySearch_Tick; 
     _tmrDelaySearch.Interval = DelayedTextChangedTimeout; 
    } 

    _tmrDelaySearch.Start(); 
} 

void _tmrDelaySearch_Tick(object sender, EventArgs e) 
{ 
    if (stcList.SelectedTab == stiTabSearch) return; 
    string word = string.IsNullOrEmpty(txtSearch.Text.Trim()) ? null : txtSearch.Text.Trim(); 

    if (stcList.SelectedTab == stiTabNote) 
    FillDataGridNote(word); 
    else 
    { 
     DataGridView dgvGridView = stcList.SelectedTab == stiTabWord ? dgvWord : dgvEvent; 
     int idType = stcList.SelectedTab == stiTabWord ? 1 : 2; 
     FillDataGrid(idType, word, dgvGridView); 
    } 

    if (_tmrDelaySearch != null) 
    _tmrDelaySearch.Stop(); 
} 
Powiązane problemy