2
\$\begingroup\$

I have a form that displays a list of days in a given month that looks like so:

Program screenshot

All the text boxes are set as readonly, which is the desired functionality. While setting enabled to false works, it gives the control a blurred out look, which is difficult to override. In order to complete them, I want to keep the user from being able to select any text.

I have bound the KeyUp and MouseUp events in the following code:

private void dateDisplay_MouseUp(object sender, MouseEventArgs e)
{
    this.dateDisplay.SelectionStart = this.dateDisplay.Text.Length;
}

private void dateDisplay_KeyUp(object sender, KeyEventArgs e)
{
    this.dateDisplay.SelectionStart = this.dateDisplay.Text.Length;
}

where dateDisplay is the left textbox.

And this what the other textbox looks like with text selected, without being wired up to any events:

Screenshot with selected text

This code prevents the user from selecting any text inside the text boxes by forcing the cursor to end of the text box. Is there a better way of doing this?

\$\endgroup\$
5
\$\begingroup\$

DRY don't repeat yourself

For each textbox you need to do the same, if you want the textbox's content to be unselectable.

So instead of calling for each textbox the shown code, you should refactor the code, by adding a method which does the same thing for any textbox.

Let us now focus on the code which should prevent the content to be selected.

this.dateDisplay.SelectionStart = this.dateDisplay.Text.Length;

If a user of the form clicks inside the textbox, e.g in the middle, an unexpected behaviour is shown, as the caret is moving magically to the end of the text.

A better way would be to use the SelectionLength property inside of these eventhandlers.
Setting the property to 0 will prevent the text to be selected, but the caret stays at the position.

The only proplem will be at the first time the form is shown, as neither of the 2 eventhandlers does fire.
Therfor you need to also use the Shown event.

Refactoring

Let us add a method RemoveSelection which takes an object as the inputparameter.

private void RemoveSelection(Object obj)
{
    TextBox textbox = obj as TextBox;
    if (textbox != null)
    {
        textbox.SelectionLength = 0;
    }
}  

now we change the eventhandler's to

private void dateDisplay_MouseUp(object sender, MouseEventArgs e)
{
    RemoveSelection(sender);
}

private void dateDisplay_KeyUp(object sender, KeyEventArgs e)
{
    RemoveSelection(sender);
}

and add the Shown eventhandler

private void MyForm_Shown(object sender, EventArgs e)
{
    RemoveSelection(dateDisplay);
}

Alternative way

If you only want to show the desired values, you should use the right tool for the job.
Instead of a TextBox you should use a Label control. To simulate the appearance of a TextBox you need to set the properties:

BorderStyle= System.Windows.Forms.BorderStyle.Fixed3D
TextAlign = ContentAlignment.MiddleLeft
AutoSize = false
Size.Height = 20

If the control which should be used, doesn't need to get the focus, then a Label is the way to go.

\$\endgroup\$
  • \$\begingroup\$ Thank you very much for the input. Unfortunately, due to the rows being displayed by adding a UserControl, there is no Shown event. I guess I can just set the focus to somewhere else on the main form... I choose the first solution you provided, to enable the user to tab through the rows \$\endgroup\$ – Mord Zuber Oct 23 '14 at 9:43
5
\$\begingroup\$

Another possible solution is to use a DataGridView. You may define a column to be read only and it will appear as normal, i.e. not grayed out when the control is not enabled. Plus I think a DataGridView would be a better solution overall given that you apparently want to displays rows of data.

\$\endgroup\$
  • \$\begingroup\$ if you were to expand this, it could be an answer \$\endgroup\$ – Malachi Oct 22 '14 at 18:00
  • 2
    \$\begingroup\$ The best code is often code that doesn't exist at all. "Don't write that code at all; try a better approach altogether" is a valid way to improve a program. Precedent for such answers: 1 2 \$\endgroup\$ – 200_success Oct 22 '14 at 18:14
  • \$\begingroup\$ There are two reasons I choose this way over a DataGrid View. 1)The Day object (in linked question) is a complex object which proved difficult to display in a DGV (I did intially try it) 2)There will be logic applied to to the UserControl in the next iteration that will cause the display to be drastically difference in special cases (a weekend for example) \$\endgroup\$ – Mord Zuber Oct 22 '14 at 18:28
  • \$\begingroup\$ But in any other case this would be the correct answer, so when my rep goes back up I will send you an upvote \$\endgroup\$ – Mord Zuber Oct 22 '14 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.