Showing posts with label Invoke. Show all posts
Showing posts with label Invoke. Show all posts

Saturday, October 8, 2016

WinForms RichTextBox Append Log and UIThread extensions

Turn any RichTextBox in winforms to a log view. Just call rtxt.AppendLog("someString"); and it will append that to a new line in the richtextbox. And scroll it to view.

public static void AppendLog(this RichTextBox rtxt, string s)
{
 rtxt.UIThread(() =>
 {
  rtxt.AppendText($"{s}{Environment.NewLine}");
  rtxt.SelectionLength = 0;
  if (rtxt.Lines.Length > 10000)
  {
   rtxt.Lines = rtxt.Lines.Skip(5000).ToArray();
  }
  rtxt.SelectionStart = rtxt.TextLength;
  rtxt.ScrollToCaret();
 });
}
The above snippet of code requires the following to function correctly.
static public void UIThread(this Control control, Action code)
{
 if (control.InvokeRequired)
 {
  control.BeginInvoke(code);
  return;
 }
 code.Invoke();
}
I can't take credit, found it years ago on some forum somewhere. But here it is anyway. It makes a call to a winforms control synschronize with the GUI thread so that no cross-threading exceptions is thrown. GUI items can only be modified from the GUI thread and this ensures just that.

The exception thrown if correct thread synchronization is not used is: 
System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Cross-thread operation not valid: Control 'rtxtOutput' accessed from a thread other than the thread it was created on.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Control.get_Handle()
       at System.Windows.Forms.TextBoxBase.GetSelectionStartAndLength(Int32& start, Int32& length)
       at System.Windows.Forms.TextBoxBase.set_SelectionLength(Int32 value)
       at System.Windows.Forms.RichTextBox.set_SelectionLength(Int32 value)
       at ave.dev.winform.Form1.ticker_Tick(Object sender, EventArgs e) in C:\tfs\YYY\Form1.cs:line 54
       at ave.dev.winform.Form1._loggerHook_NewLogLine(String s) in C:\tfs\YYY\Form1.cs:line 38


Back to extensions list