RichTextBox woes

S

sb

My app needs to load a plaintext file (1 to 15MBs), edit & convert it to
rtf, and finally output it to a RichTextBox (RTB). Simple enough...

Loading a 5MB file (average case for this app) and editing/converting it to
an rtf string takes about 1 second to accomplish...no big deal. However,
doing a "myRTB.Rtf = myRtfString;" takes another 25-30 more seconds!.
That's even after I've hidden the RTB and prevented the underlying RichEdit
control from generating WM_PAINT & other events while I'm updating it (via
SendMessage SET_REDRAW & EM_SETEVENTMASK respectively).

Anyway, I'm out of ideas when it comes to speeding up the RTB since it seems
from my research that slowness is a longstanding problem with the underlying
RichEdit. I should also mention that I don't want to get into partial
loading/editing...I've tried it...it had its own set of issues.

So in light of the above problem...is there a safe way to update the
RTB's.Rtf property from within a thread? My goal now is to:
a) update the RTB in the background thread (if possible) so I don't lost
app responsiveness
b) allow a user to cancel the operation if they choose to do so

TIA!
-sb
 
A

Andy

If you're using .Net 2.0 (not sure method exists in 1.x) you can use
the Invoke method. This would all be in your form class.

private delegate SetTextCallback( string rtfText );

public function SetText( string rtfText ) {
SetTextCallback cb;

if ( RtfBox.InvokeRequired ) {
cb = new SetTextCallback( SetText );
RtfBox.Invoke( cb, new object[] { rtfText } );
}
else {
RtfBox.Rtf = rtfText;
}
}

Your background thread would then call the SetText method.

This comes from the help: lookup Thread Safe.

Of course you would still have issues; what if the user begins typing
before your thread sets the text? Any text would be obliterated.
There may be other issues as well.

HTH
Andy
 
S

sb

Thanks for the reply and for the record, I'm using .Net 2.0.

I tried the method you mentioned below 2 days ago and it had a predictable
result....a UI hang during the update. This is because a call to Invoke
merely switches the thread context to allow the delegate to execute within
the main UI's thread context....therefore we've gained nothing by using a
separate thread...we've actually slowed things down a tad.

I need a way to do "RtfBox.Rtf = rtfText" within the context of the worker
thread. Maybe it will work if I create the RTB in a thread, do all the work
there and then pass it back to main thread to be added to the form. I'm
unclear on whether it's possible or not to do that or if it will cause
threading issues....but I'm going to give it a shot. Any thoughts are
appreciated.

-sb
 
A

Andy

Sb,

I think you may just be out of luck then. I don't think you can make a
control 'jump' to another thread. I'm pretty sure you'll get a
threading exception attempting to put a control from on thread on a
form in a different thread. Maybe there is a 3rd party control that
handles rich text and peforms better.

Post if you find a solution though; I'd like to file a solution if I
ever come across this problem myself.

Andy
 
J

Jamie Bissett

Try using the background worker thread, as this has a wrapper which allows
you to update the UI safley from another thread.
 
S

sb

I did try the background worker. I didn't see anything in that class that
allows me to handle a UI element from it though.

I tried this approach last night:

1) create a richtextbox from the main thread using "myrtb = new
RichTextBox()"
2) create a BackgroundWorker object and set up the DoWork and
RunWorkerCompleted events
3) call DoWork(myrtb)
4) In the DoWork method, do all the parsing/editing/converting to rtf of a
test text file
5) In the RunWorkerCompleted method, I try to access the newly modified
RTB's.Text property.

It all seems to go smoothly...until I get to step 5. Then I get an
TargetInvocationException on the main thread. I'm going to dig into the
cause of that exception tonight.

-sb
 
A

Andy

I think you can fix the exception you're getting by using the Invoke
method on the richtextbox control. Look for 'thread safe' in the help
index, and there will be a topic on accessing windows controls in a
thread safe manner.
 
S

sb

I realize that I can fix the error by using Invoke. As I stated in an
earlier post, that merely brings me back to the original problem...the UI
hangs while calling myRichTextBox.Rtf = myRtfString;. The problem is that
the control itself is horribly slow when loading a large amount of data. I
was hoping to create a control in a worker thread and update it there...then
once the thread has terminated, use the control in the main thread. I see
now that it's just not possible because the framework throws the
TargetInvocationException as soon as I try to access the control from a
thread other than the one that created the handle to the underlying windows
control.

My only option now is to use pinvoke to work directly with the underlying
RichEdit or...write my own RichTextBox that won't choke on large files.
Either way...it's a lot more work than I had expected to have to do.

-sb
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top