views:

1376

answers:

3

I've written a c# application to run an external program and i've redirectet it's output to a richtextbox in my form. I've created the process using the following settings

p1.StartInfo.RedirectStandardOutput = true;
p1.OutputDataReceived += new DataReceivedEventHandler(outputreceived);

and in the outputreceived event

void outputreceived(object sender, DataReceivedEventArgs e)
{
  if (!string.IsNullOrEmpty(e.Data))
  {
    richTextBox1.Invoke(new UpdateOutputCallback(this.updateoutput),
                        new object[] { e.Data });
  }
}

void updateoutput(string text)
{
  int len = text.Length;
  int start = richTextBox1.Text.Length;
  richTextBox1.Text += text + Environment.NewLine;
  richTextBox1.Select(start, len);
  richTextBox1.SelectionColor = System.Drawing.Color.White;
  richTextBox1.Select(richTextBox1.Text.Length, 0);
  richTextBox1.ScrollToCaret();
}

Now the thing is though it is working, but my main form which contains the textbox, hangs if the output is huge from the application. I think each time the invoke call leads to repainting of the form, which happens very frequently. Is there any alternative so that i can see the updates to the textbox as they happen and also keep the form completely active?


Update:

I think I got my answer, I used BeginInvoke when I should have used Invoke.


Update 1:

I tried both BeginInvoke and Suspendlayout but it is not giving me the desired functionality, what happens is that the process has returened all the standardoutput to the string, but the thread which is responsible for updating the text is taking it's own time to print the data. Can i do any thing to it?

+1  A: 

Since you've already solved your problem, I'll just note that it will be faster if you use rtb.AppendText (instead of Text += ...) and use pinvoke to scroll to the bottom:

private const int WM_VSCROLL = 0x115;
private const int SB_BOTTOM = 7;

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam,
IntPtr lParam);

// ...
// Scroll to the bottom, but don't move the caret position.
SendMessage(rtb.Handle, WM_VSCROLL, (IntPtr) SB_BOTTOM, IntPtr.Zero);
Daniel LeCheminant
+1  A: 

You might want to try

richTextBox1.BeginInvoke()

rather than

richTextBox1.Invoke()

That will at least make the call Asynchronous. Still not sure if that will cause the UI thread to lock while the updates are being painted.

Justin Niessner
If you read his update, he changed to Invoke and it works better now because the worker thread has to wait for the UI to update.
Samuel
A: 

Try to suspend and resume layout of richTextBox1

    void updateoutput(string text)
    {
        try
        {
            richTextBox1.SuspendLayout();

            int len = text.Length;
            int start = richTextBox1.Text.Length;
            richTextBox1.Text += text + Environment.NewLine;
            richTextBox1.Select(start, len);
            richTextBox1.SelectionColor = Color.White;
            richTextBox1.Select(richTextBox1.Text.Length, 0);
            richTextBox1.ScrollToCaret();
        }
        finally
        {
            richTextBox1.ResumeLayout();
        }
    }

Is there any alternative so that i can see the updates to the textbox as they happen and also keep the form completely active?

I think you should use Debug.Print to view what's going on instead.

Sung Meister