2009-10-11 61 views
7

Ứng dụng WinForms của tôi có một Hộp văn bản mà tôi đang sử dụng làm tệp nhật ký. Tôi đang thêm văn bản mà không có hình thức nhấp nháy bằng cách sử dụng TextBox.AppendText(string);, tuy nhiên khi tôi cố gắng thanh lọc văn bản cũ (như thuộc tính .Text kiểm soát đạt đến giới hạn .MaxLength), tôi nhận được nhấp nháy khủng khiếp.Dừng nhấp nháy TextBox trong khi cập nhật

Mã Tôi đang sử dụng như sau:

public static void AddTextToConsoleThreadSafe(TextBox textBox, string text) 
{ 
    if (textBox.InvokeRequired) 
    { 
     textBox.Invoke(new AddTextToConsoleThreadSafeDelegate(AddTextToConsoleThreadSafe), new object[] { textBox, text }); 
    } 
    else 
    { 
     // Ensure that text is purged from the top of the textbox 
     // if the amount of text in the box is approaching the 
     // MaxLength property of the control 

     if (textBox.Text.Length + text.Length > textBox.MaxLength) 
     { 
      int cr = textBox.Text.IndexOf("\r\n"); 
      if (cr > 0) 
      { 
       textBox.Select(0, cr + 1); 
       textBox.SelectedText = string.Empty; 
      } 
      else 
      { 
       textBox.Select(0, text.Length); 
      } 
     } 


     // Append the new text, move the caret to the end of the 
     // text, and ensure the textbox is scrolled to the bottom 

     textBox.AppendText(text); 
     textBox.SelectionStart = textBox.Text.Length; 
     textBox.ScrollToCaret(); 
    } 
} 

Có cách nào gọn gàng của thanh lọc dòng văn bản từ phía trên cùng của điều khiển mà không gây nhấp nháy? Một textbox không có các phương thức BeginUpdate()/EndUpdate() mà một ListView có.

Hộp văn bản có kiểm soát ngay cả điều khiển phù hợp nhất cho nhật ký bảng điều khiển không?

Chỉnh sửa: Nhấp nháy TextBox dường như là hộp văn bản cuộn lên trên cùng (trong khi tôi dọn dẹp văn bản ở đầu điều khiển), và sau đó ngay lập tức cuộn xuống dưới cùng. - tất cả xảy ra rất nhanh, vì vậy tôi chỉ thấy nhấp nháy lặp đi lặp lại.

Tôi cũng vừa xem this question và đề xuất là sử dụng ListBox, tuy nhiên tôi không biết điều này có hiệu quả trong trường hợp của tôi hay không (như trong hầu hết các trường hợp). một nhân vật tại một thời điểm.

+1

Có thể muốn thay đổi "nếu" thành "trong khi" - trong trường hợp xóa dòng văn bản đầu tiên không đủ để cho phép văn bản mới phù hợp với TextBox. –

+0

Cũng phát hiện Noam. Cảm ơn. – Bryan

+2

Bài đăng này có một số thông tin khác về điều này - http://stackoverflow.com/questions/1333393/how-to-prevent-a-windows-forms-textbox-from-flickering-on-resize –

Trả lời

2

Vấn đề là bạn đang thêm (loại bỏ) một ký tự cùng một lúc nhiều lần và nhanh chóng. Một giải pháp là để đệm các ký tự khi chúng được thêm vào và cập nhật hộp văn bản trong khoảng thời gian lớn hơn (bất kể số lượng ký tự), ví dụ, mỗi 250 mili giây.

này sẽ yêu cầu:

  • có một mảng hoặc chồng của nhân vật mà họ nhận được thêm
  • để có một giờ mà có thể gọi là một đại biểu mà thực sự sẽ làm bản cập nhật với các nhân vật được lưu giữ trong ngăn xếp

Một tùy chọn khác là sử dụng cả 250 ký tự và 100 ký tự, bất kỳ điều gì xảy ra trước. Nhưng điều này có thể làm phức tạp thêm mã mà không có bất kỳ lợi ích hữu hình nào.

+0

Điều đó không chỉ làm tăng tốc độ nhấp nháy? – Bryan

+0

Đó là cho tôi một ý tưởng mặc dù tôi có thể sử dụng cho đến khi tôi tìm thấy một giải pháp tốt hơn. Khi kiểm soát đầy, bây giờ tôi thanh lọc khoảng 20% ​​nội dung (tôi có thể đủ khả năng để giảm 20%, mặc dù tôi muốn có nó hoạt động đúng). Bằng cách này thay vì nhìn thấy sự nhấp nháy liên tục khi kiểm soát đầy, bạn không thể nhận thấy nó là nhấp nháy chỉ có thể xảy ra một lần một giờ thay vì vài lần một giây. – Bryan

+0

Các giai đoạn không có nhiều suy nghĩ, tôi phải thừa nhận :) –

3

Bạn đã đặt chế độ đệm đôi trên cửa sổ chính của mình chưa?

mã này trong hàm tạo của bạn sau khi cuộc gọi InitializeComponent sẽ thêm bộ đệm đôi và có thể làm giảm nhấp nháy.

this.SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer,true);

+0

Tôi đã thử điều này, tiếc là nó không tạo ra bất kỳ sự khác biệt nào. – Bryan

+0

Điều này sẽ không giúp ích gì; TextBox vốn đã rất dễ sử dụng và điều tốt nhất bạn có thể hy vọng là giảm nó. http://stackoverflow.com/questions/1333393/how-to-prevent-a-windows-forms-textbox-from-flickering-on-resize –

2

Bạn hãy thử SuspendLayout()/ResumeLayout() xung quanh tất cả các hoạt động cập nhật của bạn?

Bạn cũng có thể gọi Xóa() trên hộp văn bản sau đó gán lại văn bản cắt ngắn.

Nếu bạn cố gắng triển khai một số loại trình xem tệp nhật ký, bạn có thể sử dụng ListBox thay thế.

+0

Tôi đã thử cả hai bộ đệm kép và SuspendLayout()/ResumeLayout(), thật không may là chúng dường như không tạo ra bất kỳ sự khác biệt nào. Tôi đã cập nhật câu hỏi của mình về việc sử dụng ListBox, tôi không chắc chắn nó sẽ hoạt động do thực tế là tôi (thường) thêm một ký tự cùng một lúc. – Bryan

+0

bạn có thể cập nhật mục cuối cùng trong hộp danh sách để thêm ký tự và nếu dòng đầy, bạn có thể thêm một mục ListBox mới. – codymanix

+0

Bạn có bao gồm * tất cả * hoạt động của mình trong SuspendLayout()/ResumeLayout(), bao gồm lệnh gọi ScrollToCaret không? – codymanix

1

Tôi thấy rằng việc sử dụng SelectedText = văn bản sẽ làm giảm đáng kể nhấp nháy. Đối với bản cập nhật rất nhanh, nhấp nháy sẽ chỉ được bản địa hóa cho văn bản mới và bạn sẽ không nhận được bất kỳ hành vi lạ nào từ thanh cuộn nhảy xung quanh.

void UpdateTextBox(string message) 
{ 
    myTextBox.SelectionStart = myTextBox.Text.Length; 
    myTextBox.SelectedText = message; 
} 

Bạn cũng có thể sử dụng để ghi đè lên văn bản bằng văn bản trước đây - như bạn sẽ cần cho việc cập nhật một bộ đếm hoặc tải về tỷ lệ phần trăm ví dụ:

void UpdateTextBox(string message, int jumpBack) 
{ 
    myTextBox.SelectionStart = Math.Max(myTextBox.Text.Length - jumpBack, 0); 
    myTextBox.SelectionLength = jumpBack; 
    myTextBox.SelectedText = message; 
} 

Khác hơn thế, đó dường như không là bất kỳ phương pháp đơn giản nào để giảm nhấp nháy trong Hộp văn bản .NET.

10

Tôi tìm thấy một giải pháp tìm kiếm trên internet:

[System.Runtime.InteropServices.DllImport("user32.dll")] 

    public static extern bool LockWindowUpdate(IntPtr hWndLock); 

    internal void FillTB(TextBox tb, string mes) 
    { 
     try 
     { 
      LockWindowUpdate(tb.Handle); 

      // Do your thingies with TextBox tb 
     } 
     finally 
     { 
      LockWindowUpdate(IntPtr.Zero); 
     } 
    } 
+0

cảm ơn, làm việc cho tôi quá - trong thực tế tôi đã sử dụng phần mở rộng của mkaj –

9

Mathijs Câu trả lời là tác phẩm cho tôi. Tôi đã sửa đổi nó một chút để tôi có thể sử dụng với bất kỳ kiểm soát - một phần mở rộng kiểm soát:

namespace System.Windows.Forms 
{ 
    public static class ControlExtensions 
    { 
     [System.Runtime.InteropServices.DllImport("user32.dll")] 
     public static extern bool LockWindowUpdate(IntPtr hWndLock); 

     public static void Suspend(this Control control) 
     { 
      LockWindowUpdate(control.Handle); 
     } 

     public static void Resume(this Control control) 
     { 
      LockWindowUpdate(IntPtr.Zero); 
     } 

    } 
} 

Vì vậy, tất cả các bạn cần làm là:

myTextBox.Suspend(); 
// do something here. 
myTextBox.Resume(); 

trình tốt. Tất cả các điểm dừng nhấp nháy.

+0

cảm ơn, làm việc cho tôi quá –

+0

FYI, Điều này không hoạt động tốt nếu '// làm điều gì đó ở đây.' là một sự kiện thay đổi kích thước. – Dan

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