2009-10-11 12 views
7

Moja aplikacja WinForm ma element TextBox, którego używam jako pliku dziennika. Załączam tekst bez migotania formularzy przy użyciu TextBox.AppendText(string);, jednak gdy próbuję usunąć stary tekst (gdy właściwość .Text formantu osiągnie limit .MaxLength), dostaję okropnego migotania.Zatrzymywanie migotania pola tekstowego podczas aktualizacji

Kod używam jest następująco:

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

Czy istnieje neater sposobem oczyszczenia linii tekstu od góry kontrolą, która nie powoduje migotanie? Pole tekstowe nie ma metod BeginUpdate()/EndUpdate(), które ma ListView.

Czy kontrolka TextBox jest nawet najlepiej dopasowanym kontrolerem dla dziennika konsoli?

Edytuj: Migotanie pola TextBox wydaje się być tekstem przewijającym się do góry (podczas gdy usuwam tekst u góry kontrolki), a następnie natychmiast przewija z powrotem na dół. - wszystko dzieje się bardzo szybko, więc widzę powtarzające się migotanie.

Właśnie widziałem także this question, a propozycja polegała na użyciu ListBox, jednak nie wiem, czy to zadziała w mojej sytuacji, ponieważ (w większości przypadków) otrzymuję tekst do ListBoxa jedna postać na raz.

+1

Może chcieć zmienić to "if" na "while" - w przypadku, gdy usunięcie pierwszego wiersza tekstu nie wystarczy, aby nowy tekst pasował do TextBox. –

+0

Dobrze zauważony Noam. Dzięki. – Bryan

+2

Ten post zawiera więcej informacji na ten temat - http://stackoverflow.com/questions/1333393/how-to-prevent-a-windows-forms-textbox-from-flickering-on-resize –

Odpowiedz

2

Problem polega na tym, że dodajesz (usuwasz) jeden znak naraz wielokrotnie i szybko. Jednym z rozwiązań byłoby buforowanie znaków podczas ich dodawania i aktualizacja pola tekstowego w większych odstępach czasu (niezależnie od liczby znaków), na przykład co 250 milisekund.

Wymagałoby to:

  • mieć tablicę lub stos znaków gdzie dodawane
  • mieć zegar, który nazwałbym delegata, który będzie faktycznie aktualizację ze znaków zapisanych w stos

Inną opcją jest użycie zarówno co 250 ms, jak i 100 znaków, niezależnie od tego, co nastąpi wcześniej. Ale to prawdopodobnie skomplikowałoby kod bardziej bez żadnej wymiernej korzyści.

+0

Czy nie zwiększyłoby to wskaźnika migotania? – Bryan

+0

Dałem mi pomysł, ale mogę go wykorzystać, dopóki nie znajdę lepszego rozwiązania. Kiedy kontrola się wypełni, teraz oczyszczam około 20% zawartości (mogę sobie pozwolić na spadek o 20%, chociaż wolałbym, żeby działało to poprawnie). W ten sposób zamiast ciągle migotać, gdy kontrola jest pełna, prawdopodobnie nie zauważysz tego, ponieważ migotanie może wystąpić tylko raz na godzinę zamiast kilku razy na sekundę. – Bryan

+0

Okresy były bez większego namysłu, muszę przyznać :) –

3

Czy ustawiłeś podwójne buforowanie w głównym oknie?

ten kod w konstruktorze po wywołaniu InitializeComponent doda podwójne buforowanie i prawdopodobnie zmniejszy migotanie.

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

+0

Próbowałem tego, niestety, nie ma to znaczenia. – Bryan

+0

To nie pomoże; TextBox jest z natury migotliwy i najlepiej można go zmniejszyć. http://stackoverflow.com/questions/1333393/how-to-prevent-a-windows-forms-textbox-from-flickering-on-resize –

2

Próbowałaś SuspendLayout()/ResumeLayout() wokół wszystkich swoich operacji aktualizacji?

Można również wywołać Clear() w polu tekstowym, a następnie ponownie przypisać skróconą treść.

Jeśli spróbujesz zaimplementować jakąś przeglądarkę plików dziennika, możesz zamiast tego użyć ListBox.

+0

Próbowałem zarówno podwójne buforowanie i SuspendLayout()/ResumeLayout(), niestety nie wydaje się, żeby to miało jakikolwiek wpływ. Mam zaktualizowane pytanie dotyczące korzystania z ListBox, nie jestem pewien, że będzie działać ze względu na fakt, że I (zwykle) dodać po jednym znaku na raz. – Bryan

+0

możesz zaktualizować ostatni element w polu listy, aby dodać znak i jeśli linia jest pełna, możesz dołączyć nowy element ListBox. – codymanix

+0

Czy uwzględniłeś * wszystkie * swoich operacji w SuspendLayout()/ResumeLayout(), należy dołączyć wywołanie ScrollToCaret? – codymanix

1

Uważam, że użycie SelectedText = text znacznie zmniejszy migotanie. W przypadku bardzo szybkich aktualizacji migotanie zostanie zlokalizowane tylko w nowym tekście, a na pasku przewijania nie pojawi się żadne dziwne zachowanie.

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

Można również użyć tego, aby zastąpić tekst napisany wcześniej - jak będzie trzeba za aktualizowanie licznika lub pobierać odsetek na przykład:

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

Poza tym, nie wydaje się, aby być dowolną prostą metodą zmniejszania migotania w .NET TextBox.

10

znalazłem rozwiązanie patrząc w internecie:

[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

dziękuję, działa również dla mnie - w rzeczywistości użyłem przedłużenia mkaj –

9

Mathijs odpowiedź jest dla mnie pracuje. I zostały zmodyfikowane go lekko więc mogę korzystać z jakiejkolwiek kontroli - rozszerzenie sterowania:

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

    } 
} 

Więc wszystko co musisz zrobić, to:

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

działa dobrze. Wszystkie migotanie się zatrzymuje.

+0

dzięki, działa dla mnie też –

+0

FYI, To nie działa dobrze, jeśli '// coś tutaj. 'Jest zdarzeniem zmiany rozmiaru. – Dan

Powiązane problemy