People all over the internet are looking for some simple solution to put line numbers to multiline textbox. Today I stumbled upon a similar question asked by someone on one of the forums here. At first glance I thought this should be simple with a RichTextBox control with numbered bullets turned on. But to my surprise, I found that the .NET RichTextBox control doesn’t expose any method directly to set the numbered bullets. I googled around if there is some good workaround to it, but couldn’t find a decent solution.
OK. So here’s my solution for this problem. This uses a Panel, a ListBox and a TextBox to simulate the functionality. And there’s some trickery involved too!
Add a Panel control to your form.
Add a listBox and a TextBox inside the Panel.
Set the following properties:
BorderStyle = Fixed3D
AutoScroll = True
BorderStyle = None
ForeColor = AppWorkspace
Location = 0, 0 [Location.X = 0, Location.Y = 0]
Width = 100 [Size.Width = 100]
TabStop = False
UseTabStop = False
BorderStyle = None
Location = 50, 0 [Location.X=50, Location.Y = 0]
Multiline = True
Text = Your text goes here…
WordWrap = False
Right-click the TextBox and click “Bring To Front” from the popup menu, so that it overlaps over the ListBox. This is to ensure that the ListBox scrollbars are not visible to the user.
And now some trick. Drag the bottom edge of the ListBox, just enough for the Panel vertical scrollbar to appear. Then drag the right edge of the TextBox so that it just touches the Panel vertical scrollbar, but doesn’t cause the horizontal scrollbar to appear. And then, drag the bottom edge of the TextBox so that it is the same height as the ListBox (or set it from properties window).
If you did everything right, this is how it should look like in Design window
Now let’s proceed to add some code. We start by adding code to TextBox TextChanged event. We will synchronize line numbers here and also set the textbox height. (I’ll explain later why we need to dynamically change the height of ListBox and TextBox).
Run the code and see how it goes. It would automatically add and remove the Line numbers as and you type in the textbox.
But observe that the current row is not highlighted. And if you keep typing, as soon as text lines exceed the panel height, the cursor goes "inside" the panel. What you type is no longer visible, though it is added to textbox. Let’s fix this.
This fixes both of our problems. The current row is highlighted and the cursor remains in view, instead of going inside the Panel, when text lines exceed the panel height. When you move your keyboard up/down button, the current row selection moves along with it.
Now the last bit of problem remaining. When you click anywhere inside the textbox, the cursor moves to that line, but the line number selection is not updated. We fix that by adding this code:
Run the code and enjoy!
How & Why this Works
Now that we have got it working, let’s see how it works.
The Panel is used to give the look of a textbox. The Panel control has a scrollbar built into it. We make it look like it is the scrollbar of the textbox. The ListBox is use to show line numbers, and the TextBox is used to show the actual text. The Font (font face, font size) of ListBox and TextBox is same. So when we add numbers to listbox, it looks like it is just beside the text lines. So effectively each item in the ListBox corresponds to one line in the textbox. We synchronize the scrollbars of ListBox and Panel so that the cursor in textbox is always visible. This also keeps the current row number always highlighted.
We keep the textbox/listbox height to just fit the text inside it, so that the panel scrollbar adjusts itself appropriately. That scrollbar scrolls the textbox/listbox controls up and down instead of the contents inside them.
This textbox can be enhanced in many ways. Here are a few ideas:
- This is just a basic rig and there is no error handling code. Error handlers need to be added appropriately.
- Wrap the entire thing nicely into a user control.
- Add a horizontal scrollbar facility.
- Add properties to toggle on/off the line numbers.
- Replace the TextBox with a RichTextBox to add formatting capabilities to the control. This however adds more challenges to it. e.g. Each item’s height in the ListBox would need to be calculated and set appropriately as each line in RichTextBox would have a different height.