Entwickler-Ecke

WinForms - Wert prüfen, ob er numerisch ist


Talemantros - Sa 17.05.14 16:06
Titel: Wert prüfen, ob er numerisch ist
Hallo zusammen,
da bin ich mal wieder mit einer neuen Frage.
Ich habe eine Modellklasse gemacht, die sich selber prüfen soll, ob alles vollständig ausgefüllt wurde und habe diese über die DataSource einer BindingSource an die Felder gebunden.
Nun ist ein Feld daraus (PLZ) ein numerisches Feld und ich würde gern den Benutzer "zwingen" eine Zahl einzugeben.

Im Moment muss man zwar schon eine Zahl eingeben, wenn man dies aber nicht tut, kann man das TextFeld nicht verlassen und auch nicht Das Form schließen.
Erst wenn die Property einen Zahlenwert erkennt, kann man die anderen Funktionen auch wieder nutzen. Selbst wenn man das Feld leert, kann man den Beenden button nicht drücken.

Doof ist halt auch, dass der Benutzer keine Meldung bekommt, was er falsch gemacht hat. (auch wenn es ja eindeutig sein sollte :-) )

Code der Modellklasse

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Recycle.Logics
{
    public class Recycler
    {
        public string Company { get; set; }
        public string Street { get; set; }
        public long? Postale { get; set; }
        public string  City { get; set; }

        public bool IsValid
        {
            get
            {
                return !string.IsNullOrWhiteSpace(Company) &
                    !string.IsNullOrWhiteSpace(Street) &
                    !string.IsNullOrWhiteSpace(City) &
                    Postale.HasValue;
            }
        }
    }
}


Code des UserCOntrols


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
namespace Recycle.Controls
{
    public partial class RecyclerNeuUserControl : UserControl
    {
        long employee = 0;

        public RecyclerNeuUserControl(long uebergabe)
        {
            InitializeComponent();
            employee = uebergabe;
        }

        private void RecyclerNeuUserControl_Load(object sender, EventArgs e)
        {
            txtFirmenname.Focus();

            bsRecycler.DataSource = new Recycler();
        }

        private void btnSpeichern_Click(object sender, EventArgs e)
        {
            Recycler newRecycler = bsRecycler.DataSource as Recycler;

            if (!newRecycler.IsValid)
                MsgAusgabe.ShowError("Bitte füllen Sie alle Felder aus!");
            else
            {
                if (MsgAusgabe.AskQuestionYesNo("Wollen Sie diesen Regranulierer speichern?") == DialogResult.Yes)
                {
                    if (RecyclerMethods.CheckRecycler(newRecycler) == 1)
                    {
                        MsgAusgabe.ShowError("Dieser Regranulierer exisitiert bereits!");
                    }
                    else
                    {
                        RecyclerMethods.SetNewRecycler(newRecycler);
                        MsgAusgabe.ShowInformation("Regranulierer erfolgreich gespeichert!");
                        MySqlHistorie.SetHistorie("Regranulierer", newRecycler.Company, "Angelegt", employee);

                        bsRecycler.DataSource = new Recycler();
                        txtFirmenname.Focus();
                    }
                }
            }
        }


Weiterhin hatte ich es dann so probiert:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
        private void txtPLZ_TextChanged(object sender, EventArgs e)
        {
            long ausgabe;
            bool isNum;

            if (txtPLZ.Text != string.Empty)
            {
                isNum = long.TryParse(txtPLZ.Text.Trim(), out ausgabe);

                if (!isNum)
                {
                    MsgAusgabe.ShowError("Bitte ausschließlich Zahlen erfassen!");
                    txtPLZ.Text = string.Empty;
                    txtPLZ.Focus();
                }   
            }
        }


Wie wäre der bessere Ansatz, dass der User auch über sein Fehlverhalten informiert wird und vorallem trotzdem, wenn er das Feld einmal angeklickt hat wieder zu einem anderen springen kann und nicht gezwungen ist eine Zahl einzugeben.

Danke

Gruß

P.S: Konsequent alles auf englisch zu benennen bekomm ich noch nicht ganz hin :-( Immer wieder flutscht es durch :-D


Th69 - Sa 17.05.14 17:36

Benutze dafür am besten die Komponente ErrorProvider [http://msdn.microsoft.com/de-de/library/system.windows.forms.errorprovider%28v=vs.110%29.aspx]. Diese zeigt dann bei einem Fehler ein rotes Ausrufezeichen neben der TextBox an, s. z.B. Using Error Provider Control in Windows Forms and C# [http://www.c-sharpcorner.com/UploadFile/DipalChoksi/UsingErrorProviderContolinWindowsFormsandCSharp11242005010829AM/UsingErrorProviderContolinWindowsFormsandCSharp.aspx].


Talemantros - Sa 17.05.14 23:12

Hallo,
Das schaue ich mir morgen an.
Danke

Damit wäre aber vermutlich noch nicht behoben dass wenn man einmal in das Feld geklickt hat man nicht mehr raus kommt oder?

Gruß


Yankyy02 - Sa 17.05.14 23:42

Hallo Talemantros,

Zitat:
Damit wäre aber vermutlich noch nicht behoben dass wenn man einmal in das Feld geklickt hat man nicht mehr raus kommt oder?

Nein da du jedesmal wenn die Eingabe nicht korrekt ist den Focus auf das Steuerelement setzt. Ich würde auch nicht jedesmal nach einer Eingabe prüfen ob der Wert korrekt ist sondern wenn das Steuerelent den Focus verliert. Mittels ErrorProvider und der Methode SetError(dein Steuerelement,"Eingabe nicht Korrekt"); wie dir Th69 vorgeschlagen hat kanst du den User darauf hinweisen das seine Eingabe nicht korrekt ist. Wenn die Form geschlossen wird prüfst du mittels GetError() ob noch Fehler vorliegen. Dazu gibt es in der Klassenbibliothek ein gutes Beispiel. Hier mal der Link http://msdn.microsoft.com/de-de/library/system.windows.forms.errorprovider.geterror%28v=vs.110%29.aspx

Ich hoffe ich konnte dir damit ein wenig weiterhelfen.

MfG

Gery


Talemantros - So 18.05.14 10:04

Guten Morgen,
da habe ich mir wohl selber ein Bein gestellt :-)
Vielen Dank und schönes Wochenende


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
        private void txtPLZ_Leave(object sender, EventArgs e)
        {
            long ausgabe;
            bool isNum;

            isNum = long.TryParse(txtPLZ.Text.Trim(), out ausgabe);

            if ((!isNum) || (txtPLZ.TextLength != 5))
            {
                errorProvider1.SetError(txtPLZ, "Bitte erfassen Sie ausschließlich Zahlen!");
            }
            else
            {
                errorProvider1.Clear();
            }
        }


Gruß

EDIT:
Jetzt habe ich doch wieder das Problem, dass wenn der Fehler mal ausgelöst war und ich dann das Form verlassen will, es nur geht, wenn jemand da eine5 stellige Zahl einträgt, obwohl er es schließen möchte


Talemantros - Fr 30.05.14 20:38

Hallo,
könnte hier noch mal jemand über meine Modellklasse aus dem ersten Post drüber schauen?
Wenn ich das so habe kann man leider nicht in der TextBox die TextBox verlassen, solange dort nicht eine Zahl drin steht.
Auch geht es nicht das Form zu schließen.

Ich fände es ziemlich sinnfrei, wenn jemand dort eine Zahl eintragen muss um den Beenden Button drücken zu können.

Danke

Gruß


Th69 - Sa 31.05.14 09:34

Hallo,

so ganz verstehe ich jetzt nicht, was du beschreibst.
Laut deiner Modellklassenmethode IsValid muß unbedingt eine PLZ vorliegen (Postale.HasValue), aber andererseits soll der Benutzer keine PLZ eingeben dürfen?

P.S. Du solltest bei boolschen Bedingungen besser die Operatoren && und || benutzen und nicht die Bitoperatoren (habe ich jetzt erst gesehen).


Ralf Jansen - Sa 31.05.14 13:12

Du bindest einen long? an die TextBox heißt es muß eine Zahl sein oder null. Wenn du einmal etwas in die TextBox eingetragen und wieder gelöscht hast dann ist der Inhalt der TextBox ein leerer string. Und ein leerer string ist nun mal weder Zahl noch null. Databinding wird verhindern das du die TextBox verlässt solange das nicht aufgelöst ist.

Entweder du änderst dein Model so das für die entsprechende Property auch ein Leerstring zulässig ist, das Postleitzahlen nur Nummern sind gilt eh nur bei einem Teil der Länder ein string wäre aus diesem Grund eh geeigneter, oder du schreibst dir ein anderes TextBox Control das im Falle das die TextBox leer ist dir null zurückliefert und eben nicht einen Leerstring.
Beispiel


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public class MyLovelyNullReturningTextBox : TextBox
{
    public override string Text
    {
        get
        {
            return string.IsNullOrWhiteSpace(base.Text) ? null : base.Text;
        }
        set
        {
            base.Text = value;
        }
    }
}