I have a Windows Form with a Rich Textbox control on the form. What I want to do is make it so that each line only accepts 32 characters of text. After 32 characters, I want
The accepted answer almost works, but is a bit awkward, due to the unnecessary use of event
, explicit delegate instantiation, and non-static callback method.
I say "almost", because it also has a subtle bug: the delegate that is created for the callback is not stored in any variable, which makes it eligible for garbage collection. The garbage collector doesn't have any way to know that you've handed the delegate-wrapped-in-a-pointer to the window object, and so would eventually be able to discard the delegate which would then cause the application to crash the next time the TextBox
control needed to wrap any text.
Here is a version that is more to my liking:
public partial class Form1 : Form
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);
private const uint EM_SETWORDBREAKPROC = 0x00D0;
private delegate int SetWordBreakProc(IntPtr text, int pos_in_text, int bCharSet, int action);
private readonly SetWordBreakProc _wordBreakCallback = (text, pos_in_text, bCharSet, action) => 0;
public Form1()
{
InitializeComponent();
textBox1.HandleCreated += TextBox1_HandleCreated;
}
private void TextBox1_HandleCreated(object sender, EventArgs e)
{
IntPtr callback = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_wordBreakCallback);
SendMessage(((Control)sender).Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, callback);
}
}
The other difference here is that I initialize the word-break proc in the TextBox.HandleCreated
event handler. This accomplishes two things: first, the initialization happens as soon as possible, right after the control's handle is valid, and second, by doing the initialization this early in the process, if the TextBox.Text
property was already set, e.g. in the Designer or the form's constructor, the wrapping will still be done correctly even for that initial text.
Text pasted in later would still be fine, and of course you could even just temporarily reset the text after initialization to force recomputation of the wrapping. But IMHO it's better to just get it to work early enough in the first place.
Also note that the above require explicit initialization of each TextBox
you've added to the form. Obviously, if you wanted to apply this technique to more than one TextBox
, it would make sense to create a new TextBox
subclass that does this initialization within its own OnHandleCreated()
override method.