我如何(优雅地)将字符串转换为字符串特定部分的标签?

Gal*_*ian 20 .net c# vb.net winforms

我将在Windows窗体上的标签中输入许多字符串(我不会使用这些字符串).字符串将类似于以下内容:

"快速的棕色狐狸在猎犬身上跑了过来"

我想在标签中显示字符串,但是将TextBox精确地覆盖在缺少字母的位置.

将有300多个字符串,我正在寻找最简单,最优雅的方法.

如何为每个字符串准确地重新定位文本框?

编辑: MaskTextBox将无法正常工作,因为我需要多行支持.

Gra*_*ate 16

一种选择是使用蒙面文本框.

在您的示例中,您将掩码设置为:

"The quick brown fox jLLLed over the l\azy hound"
Run Code Online (Sandbox Code Playgroud)

这将显示为:

"The quick brown fox j___ed over the lazy hound"
Run Code Online (Sandbox Code Playgroud)

并且只允许3个字符(az和AZ)输入间隙.并且可以通过代码轻松更改掩码.

编辑:为方便起见......

以下是屏蔽字符的列表和说明

(摘自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.
Run Code Online (Sandbox Code Playgroud)

所有其他字符 - 文字.所有非掩码元素将在MaskedTextBox中显示为自身.文字在运行时始终占据掩码中的静态位置,并且不能被用户移动或删除.

  • 这将是理想的,但我刚刚意识到我需要多行支持,因为一些输入字符串长于一行. (2认同)

Rez*_*aei 6

为了满足此要求,IMO 最好使用 Windows 窗体的那些功能,这些功能允许与HTMLWPF和托管WebBrowser控件或 WPF 的互操作性以ElementHost向用户显示内容。在阅读此答案之前,请考虑:

  • 用户不应能够清除这些____字段。如果他们可以清除它们,一旦他们移动到另一个空白处,他们将失去找到已清除字段的能力。
  • 最好允许用户使用Tab键在____字段之间移动。
  • 正如问题中提到的:MaskTextBox 将无法工作,因为我需要多行支持。
  • 正如问题中提到的那样:将有 300 多个字符串,因此混合大量 Windows 窗体控件不是一个好主意。

使用 Html 作为 C# 模型的视图并在 WebBrowser 控件中显示

在这里,我将分享一个基于在WebBrowser控件中显示 HTML 的简单答案。作为一个选项,您可以使用WebBrowser控件并创建合适的 html 以WebBrowser使用模式类在控件中显示。

主要思想是基于测验模型(包括原始文本和空白的格子)创建一个 html 输出,并使用 html 呈现模型并将其显示在WebBrowser控件中。

例如使用以下模型:

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));
Run Code Online (Sandbox Code Playgroud)

它将呈现此输出:

填空 - 首字母

然后在用户输入值后,它将以这种方式显示:

填空——有答案

最后,当你点击Show Result按钮时,它会以绿色显示正确答案,以红色显示错误答案:

填空——显示结果

代码

您可以在此处下载完整的工作源代码,例如:

实现很简单:

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*/
    }
}
Run Code Online (Sandbox Code Playgroud)

下面是Quiz该类的完整代码:

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; }
}
Run Code Online (Sandbox Code Playgroud)

这是 html 模板的内容:

<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>
Run Code Online (Sandbox Code Playgroud)

  • 我不认为这有效,但 OP 要求提供 Winforms 解决方案。否则,问题将是“如何将优雅的 Web 解决方案包装到 Winforms 控件中。这也需要诸如“我知道 WPF,这是我的解决方案和 [这里是如何将它包装在 Winforms 中](https:// docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/walkthrough-hosting-a-wpf-composite-control-in-windows-forms)。 (2认同)

Jer*_*son 5

在此输入图像描述

找出点击了哪个角色,如果是下划线,则左右下划线,并在下划线顶部显示一个文本框.

您可以调整此代码,标签实际上是一个只读文本框,可以访问GetCharIndexFromPositionGetPositionFromCharIndex方法.

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private System.Windows.Forms.TextBox txtGap;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Label lblClickedOn;
        private System.Windows.Forms.TextBox txtTarget;

        private void txtTarget_MouseDown(object sender, MouseEventArgs e)
        {
            int index = txtTarget.GetCharIndexFromPosition(e.Location);
            //Debugging help
            Point pt = txtTarget.GetPositionFromCharIndex(index);
            lblClickedOn.Text = index.ToString();

            txtGap.Visible = false;

            if (txtTarget.Text[index] == (char)'_')
            {
                //Work out the left co-ordinate for the textbox by checking the number of underscores prior
                int priorLetterToUnderscore = 0;
                for (int i = index - 1; i > -1; i--)
                {
                    if (txtTarget.Text[i] != (char)'_')
                    {
                        priorLetterToUnderscore = i + 1;
                        break;
                    }
                }

                int afterLetterToUnderscore = 0;
                for (int i = index + 1; i <= txtTarget.Text.Length; i++)
                {
                    if (txtTarget.Text[i] != (char)'_')
                    {
                        afterLetterToUnderscore = i;
                        break;
                    }
                }


                //Measure the characters width earlier than the priorLetterToUnderscore
                pt = txtTarget.GetPositionFromCharIndex(priorLetterToUnderscore);
                int left = pt.X + txtTarget.Left;

                pt = txtTarget.GetPositionFromCharIndex(afterLetterToUnderscore);
                int width = pt.X + txtTarget.Left - left;

                //Check the row/line we are on
                SizeF textSize = this.txtTarget.CreateGraphics().MeasureString("A", this.txtTarget.Font, this.txtTarget.Width);
                int line = pt.Y / (int)textSize.Height;

                txtGap.Location = new Point(left, txtTarget.Top + (line * (int)textSize.Height));
                txtGap.Width = width;
                txtGap.Text = string.Empty;
                txtGap.Visible = true;

             }
        }

        private void Form1_Click(object sender, EventArgs e)
        {
            txtGap.Visible = false;
        }

        public Form1()
        {
            this.txtGap = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.lblClickedOn = new System.Windows.Forms.Label();
            this.txtTarget = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // txtGap
            // 
            this.txtGap.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.txtGap.Location = new System.Drawing.Point(206, 43);
            this.txtGap.Name = "txtGap";
            this.txtGap.Size = new System.Drawing.Size(25, 20);
            this.txtGap.TabIndex = 1;
            this.txtGap.Text = "ump";
            this.txtGap.Visible = false;
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(22, 52);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(84, 13);
            this.label2.TabIndex = 2;
            this.label2.Text = "Char clicked on:";
            // 
            // lblClickedOn
            // 
            this.lblClickedOn.AutoSize = true;
            this.lblClickedOn.Location = new System.Drawing.Point(113, 52);
            this.lblClickedOn.Name = "lblClickedOn";
            this.lblClickedOn.Size = new System.Drawing.Size(13, 13);
            this.lblClickedOn.TabIndex = 3;
            this.lblClickedOn.Text = "_";
            // 
            // txtTarget
            // 
            this.txtTarget.BackColor = System.Drawing.SystemColors.Menu;
            this.txtTarget.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.txtTarget.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.txtTarget.Location = new System.Drawing.Point(22, 21);
            this.txtTarget.Name = "txtTarget";
            this.txtTarget.ReadOnly = true;
            this.txtTarget.Size = new System.Drawing.Size(317, 16);
            this.txtTarget.TabIndex = 4;
            this.txtTarget.Text = "The quick brown fox j___ed over the l__y hound";
            this.txtTarget.MouseDown += new System.Windows.Forms.MouseEventHandler(this.txtTarget_MouseDown);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(394, 95);
            this.Controls.Add(this.txtGap);
            this.Controls.Add(this.txtTarget);
            this.Controls.Add(this.lblClickedOn);
            this.Controls.Add(this.label2);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Click += new System.EventHandler(this.Form1_Click);
            this.ResumeLayout(false);
            this.PerformLayout();
        }
    }        
}
Run Code Online (Sandbox Code Playgroud)

要禁用选中的文本框(假标签):https://stackoverflow.com/a/42391380/495455

编辑:

我使它适用于多行文本框:

在此输入图像描述