Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I (elegantly) transpose textbox over label at specific part of string?

I'll be feeding a number of strings into labels on a Windows Form (I don't use these a lot). The strings will be similar to the following:

"The quick brown fox j___ed over the l__y hound"

I want to display the string in a label but overlay a TextBox exactly where the missing letters are.

There'll be 300+ strings, and I'm looking for the simplest, most elegant way to do it.

How do I reposition the textbox accurately for each string?

EDIT: A MaskTextBox won't work as I need multiline support.

like image 886
Galwegian Avatar asked Jan 23 '18 12:01

Galwegian


People also ask

How do I change a TextBox to a label?

Select your TextBox in the Designer, go to the it's properties and click on the events (teh icon with the lightning). Then make a double click on the event that is called: TextChanged . That's it.

How do I change the text of a label in C#?

Following steps are used to set the Text property of the Label: Step 1: Create a label using the Label() constructor is provided by the Label class. // Creating label using Label class Label mylab = new Label(); Step 2: After creating Label, set the Text property of the Label provided by the Label class.

What property of the TextBox component is used to allow multiple lines of text input in the component?

You can use the Multiline and ScrollBars properties to enable multiple lines of text to be displayed or entered.


2 Answers

One option is to use a Masked Textbox.

In your example, you would set the mask to:

"The quick brown fox jLLLed over the l\azy hound"

Which would appear as:

"The quick brown fox j___ed over the lazy hound"

And only allow 3 characters (a-z & A-Z) to be entered into the gap. And the mask could be easily changed via code.

EDIT: For convenience...

Here is a list and description of masking characters

(taken from http://www.c-sharpcorner.com/uploadfile/mahesh/maskedtextbox-in-C-Sharp/).

0 - Digit, required. Value between 0 and 9.
9 - Digit or space, optional.
# - Digit or space, optional. If this position is blank in the mask, it will be rendered as a space in the Text property.
L - Letter, required. Restricts input to the ASCII letters a-z and A-Z.
? - Letter, optional. Restricts input to the ASCII letters a-z and A-Z.
& - Character, required.
C - Character, optional. Any non-control character.
A - Alphanumeric, required.
a - Alphanumeric, optional.
.  - Decimal placeholder.
, - Thousands placeholder.
: - Time separator.
/ - Date separator.
$ - Currency symbol.
< - Shift down. Converts all characters that follow to lowercase.
> - Shift up. Converts all characters that follow to uppercase.
| - Disable a previous shift up or shift down.
\ - Escape. Escapes a mask character, turning it into a literal. "\\" is the escape sequence for a backslash.

All other characters - Literals. All non-mask elements will appear as themselves within MaskedTextBox. Literals always occupy a static position in the mask at run time, and cannot be moved or deleted by the user.

like image 140
Gravitate Avatar answered Oct 31 '22 17:10

Gravitate


To satisfy this requirement, IMO it's better to use those features of Windows Forms which allow interoperability with HTML or WPF and Host a WebBrowser control or a WPF ElementHost to show the content to users. Before reading this answer, please consider:

  • Users should not be able to clear the ____ fields. If they can clear them, once they moved to another blank, they will lose the ability to find the cleared field.
  • It's better to allow users to use Tab key to move between ____ fields.
  • As it's mentioned in the question: A MaskTextBox won't work as I need multiline support.
  • As it's mentioned in the question: There'll be 300+ strings so mixing a lot of Windows Forms control is not a good idea.

Using Html as View of a C# model and show it in WebBrowser control

Here I will share a simple answer based on showing HTML in WebBrowser control. As an option you can use a WebBrowser control and create suitable html to show in WebBrowser control using a mode class.

The main idea is creating an html output based on the quiz model (including the original text and ragnes of blanks) and rendering the model using html and showing it in a WebBrowser control.

For example using following model:

quiz = new Quiz();
quiz.Text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
quiz.Ranges.Add(new SelectionRange(6, 5));
quiz.Ranges.Add(new SelectionRange(30, 7));
quiz.Ranges.Add(new SelectionRange(61, 2));
quiz.Ranges.Add(new SelectionRange(82, 6));

It will render this output:

fill in the blank - initial

Then after the user entered values, it will show this way:

fill in the blank - having answers

And at last, when you click on Show Result button, it will show the correct answers in green color, and wrong answers in red color:

fill in the blank - showing results

Code

You can download full working source code for example here:

  • r-aghaei/FillInTheBlankQuizSample

The implementation is quiet simple:

public class Quiz
{
    public Quiz() { Ranges = new List<SelectionRange>(); }
    public string Text { get; set; }
    public List<SelectionRange> Ranges { get; private set; }
    public string Render()
    {
        /* rendering logic*/
    }
}

Here is the complete code of the Quiz class:

public class Quiz
{
    public Quiz() { Ranges = new List<SelectionRange>(); }
    public string Text { get; set; }
    public List<SelectionRange> Ranges { get; private set; }
    public string Render()
    {
        var content = new StringBuilder(Text);
        for (int i = Ranges.Count - 1; i >= 0; i--)
        {
            content.Remove(Ranges[i].Start, Ranges[i].Length);
            var length = Ranges[i].Length;
            var replacement = $@"<input id=""q{i}"" 
                type=""text"" class=""editable""
                maxlength=""{length}"" 
                style=""width: {length*1.162}ch;"" />";
            content.Insert(Ranges[i].Start, replacement);
        }
        var result = string.Format(Properties.Resources.Template, content);
        return result;
    }
}

public class SelectionRange
{
    public SelectionRange(int start, int length)
    {
        Start = start;
        Length = length;
    }
    public int Start { get; set; }
    public int Length { get; set; }
}

And here is the content of the html template:

<html>
    <head>
    <meta http-equiv="X-UA-Compatible" content="IE=11" />
    <script>
        function setCorrect(id){{document.getElementById(id).className = 'editable correct';}}
        function setWrong(id){{document.getElementById(id).className = 'editable wrong';}}
    </script>
    <style>
        div {{
            line-height: 1.5;
            font-family: calibri;
        }}
        .editable {{
            border-width: 0px;
            border-bottom: 1px solid #cccccc;
            font-family: monospace;
            display: inline-block;
            outline: 0;
            color: #0000ff;
            font-size: 105%;
        }}
        .editable.correct
        {{    
            color: #00ff00;
            border-bottom: 1px solid #00ff00;
        }}
        .editable.wrong
        {{    
            color: #ff0000;
            border-bottom: 1px solid #ff0000;
        }}
        .editable::-ms-clear {{
            width: 0;
            height: 0;
        }}
    </style>
    </head>
    <body>
    <div>
    {0}
    </div>
    </body>
</html>
like image 29
Reza Aghaei Avatar answered Oct 31 '22 18:10

Reza Aghaei