Walidacja/filtrowanie danych przy wklejaniu

0

Mam textBoxa, w którym można wpisywać numer telefonu w określonym, precyzyjnym formacie (+48-54-1324658 - czyli "+", dwie cyfry, "-", dwie cyfry, "-", siedem cyfr).
Najpierw mam taką metodę obsługującą zdarzenie KeyPress:

private void textBoxNumerTelefonu_KeyPress(object sender, KeyPressEventArgs e)
        {
            if ((char.IsDigit(e.KeyChar) == false) && (e.KeyChar != '+') && (e.KeyChar != '-') && (e.KeyChar != '\b')) e.Handled = true;
        }

A następnie coś takiego (poprawnośćNumeruTelefonu obsługuje zdarzenie TextChanged):

private bool CzyNumerTelefonuPoprawny(string nazwa)
        {
            return Regex.IsMatch(nazwa, @"^+\+[0-9]{2}-[0-9]{2}-[0-9]{7}$", RegexOptions.None);
        }

        private void poprawnośćNumeruTelefonu(object sender, EventArgs e)
        {
            if (CzyNumerTelefonuPoprawny(textBoxNumerTelefonu.Text))
            {
                licznik4 = 1;
                pictureBoxNumerTelefonu.Image = imageList1.Images[1];
            }
            else
            {
                licznik4 = 0;
                pictureBoxNumerTelefonu.Image = imageList1.Images[0];
            }
            sprawdzeniePoprawności();
            textBoxNumerTelefonu.Focus();
        }

Wszystko działa, mam tylko jeden problem - przy wklejaniu tekstu ze schowka. Nie chcę całkowicie blokować takiej możliwości, chciałbym jednak, żeby po wklejeniu ze schowka tekstu zawierającego litery, cyfry i różne znaki, pozostały tylko znaki dozwolone, czyli cyfry oraz "+" i "-".
Ma ktoś jakiś pomysł, jak mogę to zrobić? Próbowałem na różne sposoby, ale nic mi nie działa.

3

Za bardzo lubisz warunki - poniższy kod:

private void poprawnośćNumeruTelefonu(object sender, EventArgs e)
{
    if (CzyNumerTelefonuPoprawny(textBoxNumerTelefonu.Text))
    {
        licznik4 = 1;
        pictureBoxNumerTelefonu.Image = imageList1.Images[1];
    }
    else
    {
        licznik4 = 0;
        pictureBoxNumerTelefonu.Image = imageList1.Images[0];
    }

    sprawdzeniePoprawności();
    textBoxNumerTelefonu.Focus();
}

możesz bez problemu zamienić na poniższy - bez stosowania warunku i powtarzania instrukcji:

private void poprawnośćNumeruTelefonu(object sender, EventArgs e)
{
    licznik4 := Convert.ToInt32(CzyNumerTelefonuPoprawny(textBoxNumerTelefonu.Text));
    pictureBoxNumerTelefonu.Image = imageList1.Images[licznik4];
    sprawdzeniePoprawności();
    textBoxNumerTelefonu.Focus();
}

Jednak wywal znaki diakrytyczne z identyfikatora, bo to podwójny błąd... choć nie składniowy, to nie wypada...


Przy wklejaniu tekstu ze schowka, najpierw waliduj go regexem; Jeśli jest poprawny to wklej go do komponentu, a jeśli nie - usuń niedozwolone znaki, przewal go regexem i jeśli jest dobry to wklej go do komponentu, a jeśli nadal zły - pokaż jakiś komunikat użytkownikowi; W każdym razie najpierw sprawdź zawartość wklejanego stringa i wklejaj go do komponentu tylko wtedy gdy jest poprawny, żeby nie stracić poprzedniej wartości z edita;

Chyba że wklejany string może zawierać niedozwolone znaki, ale informujesz o poprawności jakąś ikonką obok pola - wtedy nie będziesz potrzebował usuwać z wejściowego stringa znaków, a tylko regexem sprawdzić poprawność i ustawić odpowiednią ikonę informacyjną;

Według mnie blokowanie możliwości wpisania niedozwolonych znaków to głupota - lepiej zrobić to tak, jak to wygląda np. w formularzach rejestracyjnych; Obok każdego pola edycyjnego jest malutka ikonka, która przyjmuje grafikę ticka lub krzyżyka, w zależności od poprawności podanych informacji; Walidacja przeprowadzana jest z reguły po utracie focusa przez komponent.

0
furious programming napisał(a):

Za bardzo lubisz warunki

Lubię, może i tak.. Taka forma jest dla mnie jednak najprostsza, najbardziej intuicyjna. Mam kontakt z programowaniem i z C# od niedawna, więc na razie stosuję takie pomysły, jakie umiem :) Dziękuję za uproszczenie kodu, na pewno też się kiedyś tego nauczę. Każda taka podpowiedź jest cenna.

furious programming napisał(a):

Jednak wywal znaki diakrytyczne z identyfikatora, bo to podwójny błąd... choć nie składniowy, to nie wypada...

Bardzo słuszna uwaga, dziękuję.

furious programming napisał(a):

Przy wklejaniu tekstu ze schowka, najpierw waliduj go regexem; Jeśli jest poprawny to wklej go do komponentu, a jeśli nie - usuń niedozwolone znaki, przewal go regexem i jeśli jest dobry to wklej go do komponentu, a jeśli nadal zły - pokaż jakiś komunikat użytkownikowi; W każdym razie najpierw sprawdź zawartość wklejanego stringa i wklejaj go do komponentu tylko wtedy gdy jest poprawny, żeby nie stracić poprzedniej wartości z edita;

Chyba że wklejany string może zawierać niedozwolone znaki, ale informujesz o poprawności jakąś ikonką obok pola - wtedy nie będziesz potrzebował usuwać z wejściowego stringa znaków, a tylko regexem sprawdzić poprawność i ustawić odpowiednią ikonę informacyjną

Hmm... próbuję się zabrać za wstawienie tej słusznie wyglądającej podpowiedzi. Czyli sugestia jest taka, żeby to wszystko było pod TextChanged dla tego Textboxa? Najpierw Regex, a potem reszta. Chodzi o to, że chciałbym jednocześnie mógł obsługiwać dwie rzeczy: wpisywanie tekstu przez użytkownika (gdzie, jak pisałem, mój kod spisywał się dokładnie tak, jak tego oczekiwałem) i wklejanie ze schowka.

furious programming napisał(a):

Według mnie blokowanie możliwości wpisania niedozwolonych znaków to głupota - lepiej zrobić to tak, jak to wygląda np. w formularzach rejestracyjnych; Obok każdego pola edycyjnego jest malutka ikonka, która przyjmuje grafikę ticka lub krzyżyka, w zależności od poprawności podanych informacji; Walidacja przeprowadzana jest z reguły po utracie focusa przez komponent.

Zgadzam się, ja jednak nie mam wyjścia, takie mam wymagania.

0

Czyli sugestia jest taka, żeby to wszystko było pod TextChanged dla tego Textboxa? Najpierw Regex, a potem reszta. Chodzi o to, że chciałbym jednocześnie mógł obsługiwać dwie rzeczy: wpisywanie tekstu przez użytkownika (gdzie, jak pisałem, mój kod spisywał się dokładnie tak, jak tego oczekiwałem) i wklejanie ze schowka.

Najpierw musisz określić to jak ma wyglądać wklejanie zawartości schowka do komponentu; Czy całość ma być nadpisywana, czy dopisywana na koniec obecnego ciągu, czy wstawiana w miejsce kursora; Także przemyśl to co się będzie działo, jeśli po wklejeniu ciągu ze schowka do komponentu, całość będzie błędna;

Jeśli te rzeczy przemyślisz i wybierzesz po jednej, wtedy będzie można myśleć nad kodem.

1

Chciałbym, żeby całość była nadpisywana. Po wklejeniu: a) mają się pojawić tylko uprawnione znaki, b) przy textboxie ikonka ma być tickiem, jeśli zawartość będzie poprawna (zgodna z wzorcem z Regexa) lub krzyżykiem, jeśli zawartość nie będzie zgodna.

No to dokładnie to, o czym napisałem wcześniej:

  • zamieniasz ciąg z komponentu na nowy - pobrany ze schowka,
  • walidujesz jego zawartość regexem,
  • bazując na wyniku walidacji - ustawiasz odpowiednią ikonę obok odpowiedniego pola edycyjnego;

Dodatkowo, mam jeszcze inne textboxy, dla każdego miałem coś takiego jak licznik. Sumowałem potem ich wartość i jeśli była określona (równa ilości tetboxów) odblokowywał mi się przycisk OK.

Ja poleciłbym Ci gdzieś przechowywać stan walidacji zawartości pól edycyjnych; Nie wiem czy tak chcesz czy inaczej, w każdym razie jeśli potrzebujesz blokować/odblokowywać przycisk Ok dynamicznie (podczas wpisywania), to w zdarzeniach TextChanged wszystkich pól edycyjnych waliduj zawartość aktywnego pola, wynik sobie zapisuj, oraz sprawdź stany walidacji wszystkich pozostałych pól i na podstawie rezultatu odblokuj lub zablokuj przycisk Ok;

Współgranie zdarzeń KeyPress i TextChanged powinno umożliwić prawidłowe działanie w obu poruszanych przypadkach - odrzucanie błędnych znaków oraz blokowanie/odblokowywanie przycisku Ok;


A tak z innej beczki - osobiście denerwują mnie takie formularze reestracyjne, w których po wpisaniu czegoś źle - co prawda ikonka zmienia się na krzyżyk, jednak podpowiedź albo jest tak uboga, że nie wiadomo co się źle wpisało, albo jej w ogóle nie ma; Przydałoby się podać w jakimś dymku czy ramce informację np. o tym, jakie znaki są dozwolone, jaką długość ma mieć wartość (min/max) czy podać maskę wartości, jeśli pole edycyjne nie posiada wewnętrznych mechanizmów formatowania, do ustawienia w IO;

Ogólnie chodzi mi o sensowną podpowiedź co się wpisało źle, żeby od razu było wiadomo i łatwo było błędną wartość poprawić.

0
furious programming napisał(a):

A tak z innej beczki - osobiście denerwują mnie takie formularze reestracyjne, w których po wpisaniu czegoś źle - co prawda ikonka zmienia się na krzyżyk, jednak podpowiedź albo jest tak uboga, że nie wiadomo co się źle wpisało, albo jej w ogóle nie ma; Przydałoby się podać w jakimś dymku czy ramce informację np. o tym, jakie znaki są dozwolone, jaką długość ma mieć wartość (min/max) czy podać maskę wartości, jeśli pole edycyjne nie posiada wewnętrznych mechanizmów formatowania, do ustawienia w IO;

Ogólnie chodzi mi o sensowną podpowiedź co się wpisało źle, żeby od razu było wiadomo i łatwo było błędną wartość poprawić.

Całkowicie się z tym zgadzam. Ja mam tylko taki "problem", że staram się skopiować działanie programu, do kodu którego nie mam dostępu. Stąd nieraz dziwne rzeczy, które z chęcią rozwiązałbym inaczej.

furious programming napisał(a):

Współgranie zdarzeń KeyPress i TextChanged powinno umożliwić prawidłowe działanie w obu poruszanych przypadkach - odrzucanie błędnych znaków oraz blokowanie/odblokowywanie przycisku Ok

Dokładnie tak to obsługuję :)

A co do całości zagadnienia. Gdy obserwuję działanie oryginalnego programu mam wrażenie, że po wklejeniu ze schowka "niewłaściwe" są kasowane.

Dziękuję za wszystkie podpowiedzi, każda mi coś rozjaśnia.

1

Całkowicie się z tym zgadzam. Ja mam tylko taki "problem", że staram się skopiować działanie programu, do kodu którego nie mam dostępu.

Wystarczy sprawdzić najważniesze przypadki (lub wszystkie, jeśli nie jest ich zbyt wiele) i sprawdzić jak zachowa się aplikacja;

A co do całości zagadnienia. Gdy obserwuję działanie oryginalnego programu mam wrażenie, że po wklejeniu ze schowka "niewłaściwe" są kasowane.

Podałem Ci rozwiązanie według Twoich wymagań, co niekoniecznie popieram;

Zauważ sprzeczność - z jednej strony nie pozwalasz wprowadzić z klawiatury nieprawidłowych znaków, ale pozwalasz wkleić je ze schowka; Musisz się zastanowić, czy niedozwolone znaki mogą się znajdować w polach edycyjnych; Jeśli tak, to obie funkcje powinny na to pozwalać, a jeśli nie, to zarówno KeyPress, jak i funkcja wklejania powinny te znaki blokować/usuwać.

0
furious programming napisał(a):

Zauważ sprzeczność - z jednej strony nie pozwalasz wprowadzić z klawiatury nieprawidłowych znaków, ale pozwalasz wkleić je ze schowka; Musisz się zastanowić, czy niedozwolone znaki mogą się znajdować w polach edycyjnych; Jeśli tak, to obie funkcje powinny na to pozwalać, a jeśli nie, to zarówno KeyPress, jak i funkcja wklejania powinny te znaki blokować/usuwać.

Nie wiem, o czym myślałem wcześniej i dlaczego dopiero teraz wydaje mi się to takie oczywiste. Dziękuję.
Teraz tylko wymyślę, jak zablokować lub usunąć przy wklejaniu niechciane rzeczy i po kłopocie :)

0

Teraz tylko wymyślę, jak zablokować lub usunąć przy wklejaniu niechciane rzeczy i po kłopocie

Nic trudnego - zadeklaruj sobie np. łańcuch znaków, który zawierać będzie tylko dozwolone znaki (chyba że tych niedozwolonych jest mniej) i w pętli for sprawdź łańcuch ze schowka, przy czym jesli danego znaku z łańcucha wejściowego nie ma w łańcuchu z prawidłowymi znakami - usuwasz go; Pętlą jedź od końca łańcucha do początku - unikniesz problemu wyjścia poza zakres łańcucha;

Być może w C# jest jakaś lepsza/krótsza metoda usuwania niechcianych znaków z łańcucha, jednak ja praktycznie nie znam w ogóle ani języka, ani jego biblioteki standardowej, stąd nie podam Ci przykładu (kodu); W sumie zawartość wszystkich moich postów w tym wątku bazowana jest na szybkim zapoznaniu się z dokumentacją na MSDN o znajomości podstaw C++ sprzed 5 lat.

1 użytkowników online, w tym zalogowanych: 0, gości: 1