C# Fehler in TextBox erkennen?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

In einer einfachen TextBox kann man keine einzelnen Zeichen andersfarbig markieren.

Da es ziemlich mühsam ist, andere TextBoxen darüber zu legen, nimmt man am besten eine RichTextBox -- hier kann man einzelne Zeichen, Abschnitte etc. formatieren.

Übrigens ist die Windows-Anwendung Notepad eine TextBox mit einem Rahmen drumherum und WordPad eine RichTextBox mit einem Rahmen drumherum.

-----

Möglicher Code:

      // berechne, bis wohin eingefärbt werden soll - solange wir nicht sicher sind, dass textBox2 höchstens so viele Zeichen enthält wie richTextBox1, sollten wir das so machen, sonst kriegen wir womöglich eine IndexOutOfRangeException.
      var lgMin = Math.Min(textBox2.TextLength, richTextBox1.TextLength);

      // gehe alle Zeichen bis zur gemeinsamen Länge durch und markiere entsprechend der (Nicht-)Übereinstimmung
      for (int i = 0; i < lgMin; i++) {
        richTextBox1.Select(i, 1);
        if (textBox2.Text[i] == richTextBox1.Text[i]) {
          richTextBox1.SelectionColor = Color.Black;
        } else {
          richTextBox1.SelectionColor = Color.Red;
        }
      }

      // Rest des Originaltextes schwarz einfärben
      if (richTextBox1.TextLength - lgMin >= 0) {
        richTextBox1.Select(lgMin, richTextBox1.TextLength - lgMin);
        richTextBox1.SelectionColor = Color.Black;
      }

Ich verwende hier richTextBox1.Select(Start, Länge) -- das ist nur ein einziger Befehl statt 2 wie bei richTextbox1.SelectionStart = ... und richTextbox1.SelectionLength = ...

Das Setzen der Markierung, welches Zeichen als nächstes einzugeben ist, muss natürlich hiernach folgen. (Oder man setzt die Hintergrundfarbe auf die entsprechende Systemfarbe und ggf. die Vordergrundfarbe auch.)

Ob es auch bei Zeilenumbrüchen funktioniert, habe ich nicht probiert. Außerdem sollte man vermutlich zeilenweise vorgehen.

Allerdings wäre es vermutlich sinnvoller, richTextBox1.SelectionBackColor (Hintergrundfarbe statt Textfarbe) zu verwenden, dann fallen Fehler auch bei Leerzeichen auf.

Vielleicht ist es auch besser, die Markierungen in dem Text zu setzen, den der Benutzer eingegeben hat. Also für das Eingabefeld eine richTextBox zu nehmen statt für das Vorlagefeld. (Oder für beide.)

Woher ich das weiß:Berufserfahrung – Software-Entwickler

verreisterNutzer  09.06.2018, 18:14

Also ist es nicht möglich per TextBox die Fehler zu sehen?

0
verreisterNutzer  09.06.2018, 18:22

Es wird dadurch einfach nur der ganze Text markiert. Auch wenn nichts falsch ist. Was ich wollte ist, dass sich ein Wort verfärbt wenn es falsch geschrieben wird

0
PWolff  09.06.2018, 18:31
@verreisterNutzer

Nach dem Setzen der Einfärbungen muss natürlich wieder das nächste einzutippende Zeichen ausgewählt werden.

0
verreisterNutzer  09.06.2018, 18:35
@PWolff

Ist das so richtig?

private void textBox2_TextChanged(object sender, EventArgs e)
        {

            var anzahlAnschläge = 0;
            for (int i = 0; i < textBox2.Text.Length; i++)
            {
                anzahlAnschläge++;
                if (Char.IsUpper(textBox2.Text[i])) { anzahlAnschläge++; }
            }
            label2.Text = String.Format("Anschläge: {0}", anzahlAnschläge);

            // berechne, bis wohin eingefärbt werden soll - solange wir nicht sicher sind, dass textBox2 höchstens so viele Zeichen enthält wie richTextBox1, sollten wir das so machen, sonst kriegen wir womöglich eine IndexOutOfRangeException.
            var lgMin = Math.Min(textBox2.TextLength, richTextBox1.TextLength);

            // gehe alle Zeichen bis zur gemeinsamen Länge durch und markiere entsprechend der (Nicht-)Übereinstimmung
            for (int i = 0; i < lgMin; i++)
            {
                richTextBox1.Select(i, 1);
                if (textBox2.Text[i] == richTextBox1.Text[i])
                {
                    richTextBox1.SelectionColor = Color.Black;
                }
                else
                {
                    richTextBox1.SelectionColor = Color.Red;
                }
            }

            // Rest des Originaltextes schwarz einfärben
            if (richTextBox1.TextLength - lgMin >= 0)
            {
                richTextBox1.Select(lgMin, richTextBox1.TextLength - lgMin);
                richTextBox1.SelectionColor = Color.Black;
            }

            richTextBox1.Refresh();
        }

0
PWolff  09.06.2018, 20:45
@verreisterNutzer

Hier fehlt noch das Markieren des nächsten Buchstabens.

Vor -- oder anstelle von --

richTextBox1.Refresh();

muss noch ein

richTextBox1.Select(textBox2.TextLength, 1);

bzw. besser (falls man in textBox2 zu viel eingibt, wird hiermit die Ausnahme vermieden)

if (textBox2.TextLength < richTextBox1.TextLength) {
  richTextBox1.Select(textBox2.TextLength, 1);
} else {
  richTextBox1.Select(richTextBox1.TextLength, 0);
}
0
PWolff  09.06.2018, 20:47
@verreisterNutzer

Natürlich kann man die Fehler zählen. Dazu reicht es, vor die Schleife, wo die Übereinstimmungen geprüft werden, eine neue Variablendefinition zu setzen

var fehleranzahl = 0;

und den Block, der

richTextBox1.SelectionColor = Color.Red;

enthält, um diese Zeile zu ergänzen:

fehleranzahl++;
0
verreisterNutzer  09.06.2018, 20:50
@PWolff

Code:

charCount = textBox2.Text.Length;
            label2.Text = "Anschläge: " + charCount.ToString();

            var lgMin = Math.Min(textBox2.TextLength, richTextBox1.TextLength);
            for (int i = 0; i < lgMin; i++)
            {
                richTextBox1.Select(i, 1);
                if (textBox2.Text[i] == richTextBox1.Text[i])
                {
                    //richTextBox1.SelectionColor = Color.Black;
                    richTextBox1.SelectionStart = textBox2.Text.Length;
                    if (textBox2.TextLength < richTextBox1.TextLength)
                    {
                        richTextBox1.Select(textBox2.TextLength, 1);
                    }
                    else
                    {
                        richTextBox1.Select(richTextBox1.TextLength, 0);
                    }
                }
                else
                {
                    richTextBox1.SelectionColor = Color.Red;
                }
            }

            // Rest des Originaltextes schwarz einfärben
            if (richTextBox1.TextLength - lgMin >= 0)
            {
                richTextBox1.Select(lgMin, richTextBox1.TextLength - lgMin);
                richTextBox1.SelectionColor = Color.Black;
            }
            richTextBox1.Select(textBox2.TextLength, 1);
            richTextBox1.Refresh();

0
verreisterNutzer  09.06.2018, 20:52
@PWolff

Ja, sonst wird der ganze Text ausgewählt. Habe es auf false gestellt und es funktioniert plötzlich. Kann man auch das kopieren des Textes blockieren?

0
PWolff  09.06.2018, 20:54
@verreisterNutzer

Vor dem if-Block wird das Zeichen an der Stelle i selektiert und im "then"-Block unter if wird SelectionStart wieder auf textBox2.Text.Length gesetzt. Dadurch wird das erste Select doch sinnlos.

0
PWolff  09.06.2018, 20:56
@verreisterNutzer

Enabled-Eigenschaft auf false setzen.

Allerdings kann man den Text dann immer noch über das Windows-API auslesen (z. B. über AutoHotkey oder AutoIt).

0
PWolff  09.06.2018, 21:03
@verreisterNutzer

Ruckeln sollte es eigentlich nicht -- aber wenn doch, dann färbe das zu markierende Zeichen mit den Markierungsfarben ein:

     // einzutippendes Zeichen markieren
     if (richTextBox1.TextLength - lgMin >= 0) {
       richTextBox1.Select(lgMin, 1);
       richTextBox1.SelectionColor = SystemColors.HighlightText;
       richTextBox1.SelectionBackColor = SystemColors.Highlight;
     }

An den Anfang muss dann die Markierung zurückgenommen werden, sonst verschwindet sie nicht:

      richTextBox1.SelectAll();
      richTextBox1.SelectionColor = SystemColors.WindowText;
      richTextBox1.SelectionBackColor = SystemColors.Window;
0
verreisterNutzer  09.06.2018, 21:06
@PWolff

Man kann den Text vom oberen richTextBox kopieren und unten einfügen. Wie kann man das blockieren?

0
verreisterNutzer  09.06.2018, 21:06
@PWolff

Die Fehler sind nun nicht mehr rot.

Code:

private void textBox2_TextChanged(object sender, EventArgs e)
        {
            charCount = textBox2.Text.Length;
            label2.Text = "Anschläge: " + charCount.ToString();

            // berechne, bis wohin eingefärbt werden soll - solange wir nicht sicher sind, dass textBox2 höchstens so viele Zeichen enthält wie richTextBox1, sollten wir das so machen, sonst kriegen wir womöglich eine IndexOutOfRangeException.
            var lgMin = Math.Min(textBox2.TextLength, richTextBox1.TextLength);

            // gehe alle Zeichen bis zur gemeinsamen Länge durch und markiere entsprechend der (Nicht-)Übereinstimmung
            for (int i = 0; i < lgMin; i++)
            {
                richTextBox1.Select(i, 1);
                if (textBox2.Text[i] == richTextBox1.Text[i])
                {
                    //richTextBox1.SelectionColor = Color.Black;
                    richTextBox1.SelectionStart = textBox2.Text.Length;
                    if (textBox2.TextLength < richTextBox1.TextLength)
                    {
                        richTextBox1.Select(textBox2.TextLength, 1);
                    }
                    else
                    {
                        richTextBox1.Select(richTextBox1.TextLength, 0);
                    }
                }
                else
                {
                    richTextBox1.SelectionColor = Color.Red;
                }
            }

            // Rest des Originaltextes schwarz einfärben
            richTextBox1.SelectAll();
            richTextBox1.SelectionColor = SystemColors.WindowText;
            richTextBox1.SelectionBackColor = SystemColors.Window;
            if (richTextBox1.TextLength - lgMin >= 0)
            {
                richTextBox1.Select(lgMin, 1);
                richTextBox1.SelectionColor = SystemColors.HighlightText;
                richTextBox1.SelectionBackColor = SystemColors.Highlight;
            }
            richTextBox1.Refresh();
        }

0
PWolff  09.06.2018, 21:08
@verreisterNutzer

Wenn richTextBox1.Enabled == false ist, sollte man mit dem Text gar nichts mehr machen können.

Wenn die Einfärbung stört, kann man die Box in einen Container packen, der Enabled == false hat.

0
PWolff  09.06.2018, 21:09
@verreisterNutzer

Hast du das Konzept der Schleife verstanden?

(Ich meine generell das Konzept der Wiederholung bestimmter Programmanweisungen.)

0
PWolff  09.06.2018, 21:11
@verreisterNutzer

Dann überleg dir, in welcher Zeile welcher Bereich des Textes markiert ist und folglich von den Formatierungen betroffen ist. Und welche Textbereiche mehrfach formatiert werden -- bei jedem Schleifendurchlauf einmal.

0
verreisterNutzer  09.06.2018, 21:13
@PWolff

Passt dieser Code nicht?

private void textBox2_TextChanged(object sender, EventArgs e)
        {
            charCount = textBox2.Text.Length;
            label2.Text = "Anschläge: " + charCount.ToString();

            // berechne, bis wohin eingefärbt werden soll - solange wir nicht sicher sind, dass textBox2 höchstens so viele Zeichen enthält wie richTextBox1, sollten wir das so machen, sonst kriegen wir womöglich eine IndexOutOfRangeException.
            var lgMin = Math.Min(textBox2.TextLength, richTextBox1.TextLength);

            // gehe alle Zeichen bis zur gemeinsamen Länge durch und markiere entsprechend der (Nicht-)Übereinstimmung
            for (int i = 0; i < lgMin; i++)
            {
                richTextBox1.Select(i, 1);
                if (textBox2.Text[i] == richTextBox1.Text[i])
                {
                    //richTextBox1.SelectionColor = Color.Black;
                    richTextBox1.SelectionStart = textBox2.Text.Length;
                    if (textBox2.TextLength < richTextBox1.TextLength)
                    {
                        richTextBox1.Select(textBox2.TextLength, 1);
                    }
                    else
                    {
                        richTextBox1.Select(richTextBox1.TextLength, 0);
                    }
                }
                else
                {
                    richTextBox1.SelectionColor = Color.Red;
                }
            }

            // Rest des Originaltextes schwarz einfärben
            if(richTextBox1.TextLength - lgMin >= 0) {
                richTextBox1.SelectAll();
                richTextBox1.SelectionColor = SystemColors.WindowText;
                richTextBox1.SelectionBackColor = SystemColors.Window;
                richTextBox1.Select(lgMin, 1);
                richTextBox1.SelectionColor = SystemColors.HighlightText;
                richTextBox1.SelectionBackColor = SystemColors.Highlight;
            }
            richTextBox1.Select(textBox2.TextLength, 1);
            richTextBox1.Refresh();
        }

0
PWolff  09.06.2018, 21:40
@verreisterNutzer
                   //richTextBox1.SelectionColor = Color.Black;

Warum hast du diese Zeile auskommentiert? (Ok, es geht schneller ohne diese Zeile. Kann man machen, wenn man vor der Schleife allen Text auf Schwarz setzt.)

                    richTextBox1.SelectionStart = textBox2.Text.Length;
                    if (textBox2.TextLength < richTextBox1.TextLength)
                    {
                        richTextBox1.Select(textBox2.TextLength, 1);
                    }
                    else
                    {
                        richTextBox1.Select(richTextBox1.TextLength, 0);
                    }


Was soll dieser Block in der Schleife?

            richTextBox1.Select(textBox2.TextLength, 1);

schadet nicht, ist aber ohne Wirkung, wenn richTextBox1.HideSelection == true

            richTextBox1.Refresh();

ist normalerweise überflüssig (bevor ich auf HideSelection gekommen bin, hatte ich hierauf getippt, weil man manchmal ein Refresh braucht, obwohl sich alle Controls neu zeichnen sollten, wenn ein Ereignishandler abgeschlossen ist)

1
verreisterNutzer  09.06.2018, 21:44
@PWolff

Jetziger Code:

private void textBox2_TextChanged(object sender, EventArgs e)
        {
            charCount = textBox2.Text.Length;
            label2.Text = "Anschläge: " + charCount.ToString();

            // berechne, bis wohin eingefärbt werden soll - solange wir nicht sicher sind, dass textBox2 höchstens so viele Zeichen enthält wie richTextBox1, sollten wir das so machen, sonst kriegen wir womöglich eine IndexOutOfRangeException.
            var lgMin = Math.Min(textBox2.TextLength, richTextBox1.TextLength);

            // gehe alle Zeichen bis zur gemeinsamen Länge durch und markiere entsprechend der (Nicht-)Übereinstimmung
            for (int i = 0; i < lgMin; i++)
            {



                richTextBox1.Select(i, 1);
                if (textBox2.Text[i] == richTextBox1.Text[i])
                {
                    richTextBox1.SelectionStart = textBox2.Text.Length;
                    if (textBox2.TextLength < richTextBox1.TextLength)
                    {
                        richTextBox1.Select(textBox2.TextLength, 1);
                    }
                    else
                    {
                        richTextBox1.Select(richTextBox1.TextLength, 0);
                    }
                }
                else
                {
                    richTextBox1.SelectionColor = Color.Red;
                }
            }

            // Rest des Originaltextes schwarz einfärben
            if (richTextBox1.TextLength - lgMin >= 0)
            {
                richTextBox1.Select(lgMin, richTextBox1.TextLength - lgMin);
                richTextBox1.SelectionColor = Color.Black;
            }

            richTextBox1.Refresh();
        }

Nun wird alles ausgewählt

0
PWolff  09.06.2018, 21:49
@verreisterNutzer

Nanu?

Und wieso ist

                    richTextBox1.SelectionStart = textBox2.Text.Length;
                    if (textBox2.TextLength < richTextBox1.TextLength)
                    {
                        richTextBox1.Select(textBox2.TextLength, 1);
                    }
                    else
                    {
                        richTextBox1.Select(richTextBox1.TextLength, 0);
                    }

immer noch in der Schleife?

0
PWolff  10.06.2018, 00:21
@verreisterNutzer

Der Block aus meinem vorigen Kommentar gehört nach die Schleife.

Falls richTextBox1.HideSelection==true, sollte auf diesen Block noch das Einfärben mit den Auswahlfarben ("Highlight...") folgen.

1
verreisterNutzer  10.06.2018, 19:53
@PWolff

oh ok. was ist noch falsch? Oder kann man es so machen, dass wenn man 10 Minuten geschrieben hat, die Fehler in einem neuen Fenster kommen, und man es von dort aus druckt?

0
PWolff  10.06.2018, 22:09
@verreisterNutzer

Auch das geht natürlich.

Aber um weiter zu analysieren, bräuchte ich den Quelltext.

(Ich hätte auch ein Beispielprojekt, aber unvollständig und mit vielen nicht unbedingt anfängertypischen Bestandteilen)

1
verreisterNutzer  11.06.2018, 18:16
@PWolff

Ich kann die Fehler nicht zählen. Es kommt immer 1/0 Raus:

private void beendenToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            this.Size = new System.Drawing.Size(898, 627);
            label1.Visible = true;
            label3.Visible = true;
            label4.Visible = true;
            textBox1.Visible = true;
            textBox3.Visible = true;
            textBox4.Visible = true;
            button1.Visible = true;
            richTextBox1.HideSelection = true;
            textBox2.HideSelection = true;
            textBox2.ReadOnly = true;


            // berechne, bis wohin eingefärbt werden soll - solange wir nicht sicher sind, dass textBox2 höchstens so viele Zeichen enthält wie richTextBox1, sollten wir das so machen, sonst kriegen wir womöglich eine IndexOutOfRangeException.
            var lgMin = Math.Min(textBox2.TextLength, richTextBox1.TextLength);


        
            // gehe alle Zeichen bis zur gemeinsamen Länge durch und markiere entsprechend der (Nicht-)Übereinstimmung
            for (int i = 0; i < lgMin; i++)
            {
                richTextBox1.Select(i, 1);
                if (textBox2.Text[i] == richTextBox1.Text[i])
                {
                    richTextBox1.SelectionColor = Color.Black;
                }
                else
                {
                    richTextBox1.SelectionColor = Color.Red;
                }

                
            }

            // Rest des Originaltextes schwarz einfärben
            if (richTextBox1.TextLength - lgMin >= 0)
            {
                richTextBox1.Select(lgMin, richTextBox1.TextLength - lgMin);
                richTextBox1.SelectionColor = Color.Black;
            }
        }

0
verreisterNutzer  11.06.2018, 18:21
@PWolff

Falscher quelltext sorry, und hat funktioniert. habe aus versehen var fehleranzahl = 0 in for {} reingetan. Hat nun geklappt. Wie kann man den einen 10Min Timer erstellen, welche nach 10 Minuten das schreiben verbietet?

0