2009-03-22 30 views
16

Chúc mừng tất cả,.NET --- Textbox control - đợi cho đến khi người dùng gõ xong

Có cách nào để biết khi nào người dùng nhập xong vào hộp văn bản? (Trước khi nhấn tab, hoặc di chuyển chuột) Tôi có một truy vấn cơ sở dữ liệu xảy ra trên sự kiện textchanged và mọi thứ hoạt động hoàn hảo. Tuy nhiên, tôi nhận thấy rằng có một chút chậm trễ của khóa học bởi vì nếu người dùng nhanh chóng gõ vào hộp văn bản chương trình đang bận làm một truy vấn cho mỗi ký tự. Vì vậy, những gì tôi đã hy vọng cho là một cách để xem nếu người dùng đã gõ xong. Vì vậy, nếu họ gõ "a" và dừng lại sau đó một sự kiện cháy. Tuy nhiên, nếu họ gõ "tất cả các cách" sự kiện cháy sau khi khóa y.

Tôi có một số ý tưởng nổi trên đầu nhưng tôi chắc chắn rằng chúng không hiệu quả nhất. Giống như đo thời gian kể từ sự kiện textchange cuối cùng và nếu nó là> hơn một giá trị nhất định thì nó sẽ tiếp tục chạy phần còn lại của các thủ tục của tôi.

cho tôi biết suy nghĩ của bạn.

Ngôn ngữ: VB.NET Khung: "done gõ" Net 2.0

--Edited để làm rõ "thực hiện gõ"

Trả lời

34

Một cách tiếp cận:

  1. Tạo một Timer với một Interval mili giây X

    Khoảng nên khoảng 300ms; hơn một thời gian bình thường giữa các tổ hợp phím, và cũng có thời gian hợp lý để chờ đợi giữa hoàn thiện và cập nhật xảy ra

  2. Trong trường hợp của đầu vào TextChanged, Stop() và sau đó Start() các Timer

    này sẽ khởi động lại Timer nếu nó đã được đang chạy, vì vậy nếu người dùng tiếp tục nhập ở tốc độ bình thường, mỗi thay đổi sẽ khởi động lại bộ hẹn giờ.

  3. Trong trường hợp Tick của timer, Stop() các Timer và thực hiện giao dịch dài

  4. Tùy chọn: Xử lý các LeaveKeyDown sự kiện để rời khỏi sự kiểm soát hoặc nhấn Nhập sẽ Stop() các Timer và làm dài Giao dịch.

Điều này sẽ gây ra cập nhật nếu văn bản đã thay đổi và người dùng không thực hiện bất kỳ thay đổi nào trong X mili giây.

Một vấn đề với phương pháp "Đo thời gian từ lần cập nhật cuối cùng" mà bạn đang xem xét là nếu thay đổi cuối cùng được thực hiện nhanh chóng, cập nhật sẽ không xảy ra và sẽ không có bất kỳ thay đổi nào sau đó để kích hoạt một kiểm tra khác.

Lưu ý: Phải có một cặp một đến một cặp giữa TextBox es và Timer s; nếu bạn đang lập kế hoạch thực hiện điều này với nhiều hơn một đầu vào, tôi sẽ xem xét việc xây dựng một UserControl kết thúc tốt đẹp chức năng này.

+0

Khá nhiều cách tiếp cận chúng tôi sử dụng. –

+0

Kế hoạch tốt, cảm ơn bạn đã đề xuất. Cho giá trị ms cũng khá hữu ích cảm ơn bạn. –

+0

@Cj Anderson: Bạn có thể phải chơi với nó một chút để tìm sự cân bằng giữa sự đáp ứng và tốc độ gõ –

1

Nó phụ thuộc vào những gì bạn có ý nghĩa bởi Có một sự kiện để cho bạn biết khi nào người dùng đã rời khỏi tiêu điểm của điều khiển cụ thể đó. Ngoài ra, có một thay đổi thậm chí còn cho bạn biết khi văn bản thay đổi. Những gì bạn có thể làm là cái bẫy hai điều:

1) Lost tập trung

2) Mỗi ​​khi người dùng thay đổi các văn bản, bắt đầu một giờ cho biết, 20 giây, và nếu người dùng được thực hiện trong thời gian đó, sau đó người dùng được gõ "xong". Đó là nếu người dùng đã không làm bất cứ điều gì trong thời gian đó thì giả sử người dùng được "thực hiện".

Nếu một trong hai điều sau xảy ra thì người dùng hoàn tất, đảm bảo dừng và khởi động lại bộ hẹn giờ một cách thích hợp. Rõ ràng, bạn có thể thay đổi thời gian chờ.

Tất cả phụ thuộc vào cách bạn muốn xác định.

+0

gì "và nếu người dùng được thực hiện trong thời gian đó "có nghĩa là gì? Rằng họ đã không gõ bất kỳ ký tự bổ sung? –

+0

Có, xin lỗi, tôi đã chỉnh sửa bài đăng để phản ánh điều này. – BobbyShaftoe

0

Cách tiếp cận tôi đã sử dụng thành công trong quá khứ sử dụng sự kiện đặt lại thủ công và lời gọi không đồng bộ để phát hiện khi người dùng đã ngừng nhập. Mã trông giống như thế này

// use manual reset event to Q up waiting threads. 
// each new text changed event clears the Q 
// only the last changed will hit the timeout, triggering the action 
private ManualResetEvent _delayMSE; 
private Func<bool> TBDelay =() => !_delayMSE.WaitOne(600, false); 
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    SendOrPostCallback ActionToRunWhenUserStopsTyping = o => 
    { 
     // ... 
    }; 

    _delayMSE.Set(); // open the ResetEvent gate, to discard these delays 
    Thread.Sleep(0); // let all pending through the gate 
    _delaySearchMSE.Reset(); // close the gate 
    TBDelay.BeginInvoke(res => 
    { 
     // callback code 
     // check how we exited, via timeout or signal. 
     bool timedOut = TBDelay.EndInvoke(res); 
     if (timedOut) 
      Dispatcher.Invoke(DispatcherPriority.Input, 
          ActionToRunWhenUserStopstyping,null); 
    }, null); 
} 
3

Tôi đã kết thúc việc thử Scott Weinstein trả lời mặc dù cần một số kiến ​​thức sâu hơn về luồng, đại biểu và cú pháp lambda cơ bản. Và nó hoạt động khá tốt. Câu trả lời ban đầu của anh ấy không phải là bản sao chép thuần túy vì vậy tôi phải làm một số trò chơi để làm cho nó hoạt động.

Tôi đã thêm rất ít thời gian vào Thread.Sleep, vì tôi nhận thấy phương thức gọi có thể xảy ra hai lần nếu người dùng gõ thực sự nhanh chóng nhưng với độ trễ ngẫu nhiên nhỏ giữa một số tổ hợp phím. Bạn cũng phải thêm tham chiếu đến WindowsBase assembly để sử dụng Dispatcher.

Tôi sử dụng 1,5 giây để đợi nhập cuối người dùng.

// use manual reset event to Q up waiting threads. 
    // each new text changed event clears the Q 
    // only the last changed will hit the timeout, triggering the action 
    private ManualResetEvent _delayMSE; 
    private Func<bool> TBDelay; 
    private delegate void ActionToRunWhenUserStopstyping(); 

    public Form1() 
    { 
     InitializeComponent(); 

     _delayMSE = new ManualResetEvent(false); 
     TBDelay =() => !_delayMSE.WaitOne(1500, false); 
    } 

    private void textBox1_TextChanged(object sender, EventArgs e) 
    { 
     _delayMSE.Set(); 

     // open the ResetEvent gate, to discard these delays  
     Thread.Sleep(20); 
     // let all pending through the gate  
     _delayMSE.Reset(); 
     // close the gate 
     TBDelay.BeginInvoke(res =>  
     {   
      // callback code   
      // check how we exited, via timeout or signal.   
      bool timedOut = TBDelay.EndInvoke(res); 
      if (timedOut) 
       Dispatcher.CurrentDispatcher.Invoke(
        new ActionToRunWhenUserStopstyping(DoWhatEverYouNeed), 
        DispatcherPriority.Input); 
     }, null); 
    } 

    private void DoWhatEverYouNeed() 
    { 
     MessageBox.Show(textBox1.Text); 
    } 
5

Đối với những người cần một cái gì đó như thế này trong .NET 2.0, ở đây tôi đã thực hiện một điều rằng xuất phát từ TextBox và sử dụng phương pháp tương tự .. Hy vọng điều này giúp đỡ

public partial class TextBox : System.Windows.Forms.TextBox 
{ 

    private ManualResetEvent _delayMSE; 
    public event EventHandler OnUserStopTyping; 
    private delegate bool TestTimeout(); 

    public TextBox() 
    { 
     _delayMSE = new ManualResetEvent(false); 
     this.TextChanged += new EventHandler(TextBox_TextChanged); 
    } 

    void TextBox_TextChanged(object sender, EventArgs e) 
    { 


     _delayMSE.Set(); 
     Thread.Sleep(20); 
     _delayMSE.Reset(); 

     TestTimeout tester = new TestTimeout(TBDelay); 
     tester.BeginInvoke(new AsyncCallback(Test), tester); 

    } 


    private void Test(IAsyncResult pResult) 
    { 
     bool timedOut = (bool)((TestTimeout)pResult.AsyncState).EndInvoke(pResult); 
     if (timedOut) 
     { 
      if (OnUserStopTyping != null) 
       OnUserStopTyping(this, null); 
     } 
    } 

    private bool TBDelay() 
    { 
     return !_delayMSE.WaitOne(500, false); 
    } 

} 
+0

Giải pháp tốt. Tôi đã điều chỉnh mã của bạn thành mã của tôi. Mở rộng sự kiện OnUserStopTyping và hiện đang làm việc cho tôi. Cảm ơn bạn đã giúp đỡ. –

Các vấn đề liên quan