Visual studio c# przy użyciu maszyn stanów w celu ograniczenia danych wejściowych w polu tekstowym. Dołączone właściwości, aby ograniczyć wprowadzanie tekstu

Leki przeciwgorączkowe dla dzieci są przepisywane przez pediatrę. Ale zdarzają się sytuacje awaryjne dotyczące gorączki, kiedy dziecko musi natychmiast otrzymać lekarstwo. Wtedy rodzice biorą na siebie odpowiedzialność i stosują leki przeciwgorączkowe. Co wolno dawać niemowlętom? Jak obniżyć temperaturę u starszych dzieci? Jakie leki są najbezpieczniejsze?

WPF nie jest nową technologią na rynku, ale dla mnie stosunkowo nową. I jak to często bywa przy nauce czegoś nowego, istnieje chęć/potrzeba wynalezienia rowerów z kwadratowymi kołami i felgami aluminiowymi, aby rozwiązać typowe problemy.

Jednym z takich zadań jest ograniczenie danych wprowadzanych przez użytkownika do określonych danych. Na przykład, powiedzmy, że chcemy, aby jedno pole tekstowe akceptowało tylko wartości całkowite, drugie akceptowało datę w określonym formacie, a trzecie akceptowało tylko liczby zmiennoprzecinkowe. Oczywiście ostateczna walidacja takich wartości nadal będzie miała miejsce w modelach widoku, ale takie ograniczenia wejściowe sprawiają, że interfejs użytkownika jest bardziej przyjazny.

W Windows Forms to zadanie zostało rozwiązane dość łatwo, a gdy ten sam TextBox z DevExpress był dostępny z wbudowaną możliwością ograniczenia danych wejściowych za pomocą wyrażeń regularnych, wszystko było ogólnie proste. Istnieje wiele przykładów rozwiązania tego samego problemu w WPF, z których większość sprowadza się do jednej z dwóch opcji: użycia dziedziczenia klasy TextBox lub dodania dołączonej właściwości z niezbędnymi ograniczeniami.

NOTATKA
Jeśli nie interesuje Cię moje rozumowanie, ale od razu potrzebujesz przykładów kodu, możesz pobrać cały projekt
WpfEx z GitHub lub pobierz główną implementację, która jest zawarta w TextBoxBehavior.cs i TextBoxDoubleValidator.cs .

Cóż, zaczynajmy?

Ponieważ dziedziczenie wprowadza dość ścisłe ograniczenie, osobiście wolę w tym przypadku używać dołączonych właściwości, ponieważ ten mechanizm pozwala ograniczyć zastosowanie tych właściwości do kontrolek określonego typu (nie chcę tej dołączonej właściwości JestPodwójny można zastosować do TextBlock, dla którego nie ma to sensu).
Ponadto należy zauważyć, że podczas ograniczania wprowadzania danych przez użytkownika nie można używać żadnych określonych separatorów liczb całkowitych i ułamkowych (takich jak „.” (kropka) lub „,” (przecinek)), a także znaków „+” i „ -', ponieważ wszystko zależy od ustawień regionalnych użytkownika.
Aby zaimplementować możliwość ograniczenia wprowadzania danych, musimy przechwycić zdarzenie wejściowe użytkownika, przeanalizować je i odrzucić te zmiany, jeśli nam nie odpowiadają. W przeciwieństwie do Windows Forms, który wykorzystuje parę zdarzeń XXXZmieniono oraz XXXZmiana, WPF używa wersji zapoznawczych zdarzeń w tym samym celu, które mogą być przetwarzane w taki sposób, że zdarzenie główne nie jest uruchamiane. (Klasyczny przykład to obsługa zdarzeń myszy lub klawiatury, które wyłączają niektóre klawisze lub ich kombinacje).

I wszystko byłoby dobrze, gdyby klasa TextBox wraz ze zdarzeniem TextChanged również zawierała Zmieniono tekst podglądu, który może zostać przetworzony i „przerwać” dane wprowadzone przez użytkownika, jeśli uznamy, że wprowadzony tekst jest nieprawidłowy. A ponieważ nie istnieje, każdy musi wymyślić własną lisapet.

Rozwiązanie problemu

Rozwiązaniem problemu jest utworzenie klasy TextBoxBehavior, która zawiera dołączoną właściwość IsDoubleProperty, po ustawieniu której użytkownik nie będzie mógł wpisać w to pole tekstowe niczego poza znakami +, -. (liczba całkowita i separator dziesiętny), a także liczby (nie zapominaj, że musimy użyć ustawień bieżącego strumienia, a nie wartości zakodowanych na sztywno).

Klasa publiczna TextBoxBehavior ( // Załączona właściwość typu logicznego, ustawienie, które ograniczy dane wejściowe użytkownika public static readonly DependencyProperty IsDoubleProperty = DependencyProperty.RegisterAttached("IsDouble", typeof (bool), typeof (TextBoxBehavior), nowe FrameworkPropertyMetadata(false, OnChangeI)) ; // Ten atrybut nie pozwala na używanie IsDouble z żadnymi // elementami interfejsu użytkownika innymi niż TextBox lub jego potomkami public static bool GetIsDouble(DependencyObject element) () public static void SetIsDouble(DependencyObject element, wartość bool) () / / Called gdy TextBoxBehavior.IsDouble="True" jest ustawiony w XAML private static void OnIsDoubleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) ( // Street magic ) )

Główna złożoność implementacji handlera Wprowadzanie tekstu podglądu(podobnie jak przypadek wklejania tekstu ze schowka) polega na tym, że w argumentach zdarzenia przekazywana jest nie całkowita wartość tekstu, a jedynie nowo wpisana jego część. Dlatego tekst podsumowujący musi być tworzony ręcznie, biorąc pod uwagę możliwość zaznaczenia tekstu w TextBox, aktualną pozycję w nim kursora i ewentualnie stan przycisku Wstaw (którego nie będziemy analizować):

// Wywoływana, gdy TextBoxBehavior.IsDouble="True" jest ustawiona w XAML private static void OnIsDoubleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) ( // Ponieważ ograniczyliśmy naszą załączoną właściwość tylko do klasy // TextBox lub jej potomków, następujące transformacja is - safe var textBox = (TextBox) d; // Teraz musimy zająć się dwoma ważnymi przypadkami: // 1. Ręczne wprowadzanie danych przez użytkownika // 2. Wklejanie danych ze schowka textBox.PreviewTextInput += PreviewTextInputForDouble; DataObject.AddPastingHandler( textBox, OnPasteForDouble ); )

Klasa TextBoxDoubleValidator

Drugim ważnym punktem jest implementacja logiki walidacji nowo wprowadzonego tekstu, za którą odpowiedzialność przypisana jest do metody Jest ważna oddzielna klasa Podwójny weryfikator pola tekstowego.

przez większość w prosty sposób zrozumieć, jak powinna zachowywać się metoda Jest ważna tej klasy jest napisanie dla niego testu jednostkowego, który obejmie wszystkie przypadki skrajne (to tylko jeden z tych przypadków, w których sparametryzowane testy jednostkowe rządzą ze straszliwą siłą):

NOTATKA
Tak właśnie jest, gdy test jednostkowy to nie tylko test sprawdzający poprawność implementacji określonej funkcjonalności. Jest to dokładnie ten przypadek, o którym wielokrotnie mówił Kent Beck, opisując odpowiedzialność; Czytając ten test można zrozumieć, o czym myślał twórca metody walidacji, „ponownie wykorzystać” swoją wiedzę i znaleźć błędy w jego rozumowaniu, a więc prawdopodobnie w kodzie implementacyjnym. To nie tylko zestaw testów - to ważna część specyfikacji tej metody!

Private static void PreviewTextInputForDouble(object sender, TextCompositionEventArgs e) ( // e.Text zawiera tylko nowy tekst, więc bieżący // stan pola tekstowego jest niezbędny var textBox = (TextBox)sender; string fullText; // Jeśli pole tekstowe zawiera zaznaczony tekst, a następnie zastąp go e.Text if (textBox.SelectionLength > 0) ( fullText = textBox.Text.Replace(textBox.SelectedText, e.Text); ) else ( // W przeciwnym razie musimy wstawić nowy tekst pozycja kursora fullText = textBox.Text.Insert(textBox.CaretIndex, e.Text); ) // Teraz sprawdź poprawność wynikowego tekstu logicznego isTextValid = TextBoxDoubleValidator.IsValid(fullText); // I zapobiegaj zdarzeniu TextChanged, jeśli tekst nie jest prawidłowy e.Handled = !isTextValid; )

Metoda testowa powraca PRAWDA jeśli parametr tekst jest prawidłowy, co oznacza, że ​​odpowiedni tekst można wpisać w pole tekstowe z dołączoną właściwością IsDouble. Zwróć uwagę na kilka rzeczy: (1) użycie atrybutu UstawKultura, który ustawia żądane ustawienia regionalne i (2) niektóre wartości wejściowe, takie jak „-.”, które nie są poprawnymi wartościami dla typu Podwójnie.

Aby testy nie kończyły się niepowodzeniem dla programistów z innymi ustawieniami osobistymi, potrzebne jest wyraźne ustawienie lokalizacji, ponieważ w rosyjskich lokalizacjach jako separator używany jest symbol „,” (przecinek), a w amerykańskim – „.” (kropka) ). Dziwny tekst, taki jak „-”. jest poprawne, ponieważ potrzebujemy, aby użytkownik uzupełnił dane wejściowe, jeśli chce wprowadzić ciąg „-.1”, który jest poprawną wartością dla Podwójnie. (Co ciekawe, StackOverflow jest bardzo często zalecany, aby po prostu użyć Double.TryParse do rozwiązania tego problemu, co oczywiście nie zadziała w niektórych przypadkach).

NOTATKA
Nie chcę zaśmiecać artykułu szczegółami implementacji metody Jest ważna, chcę tylko zwrócić uwagę na użycie metody ThreadLocal w treści tego , który pozwala na pobieranie i buforowanie Podwójny separator lokalne dla każdego wątku. Pełna implementacja metody TextBoxDoubleValidator.IsValid możesz znaleźć więcej informacji na temat WątekLokalny Możesz przeczytać artykuł Joe Albahari Praca z wątkami. Część 3 .

Alternatywne rozwiązania

Oprócz przechwytywania wydarzeń Wprowadzanie tekstu podglądu i wklejanie tekstu ze schowka, istnieją inne rozwiązania. Na przykład spotkałem się z próbą rozwiązania tego samego problemu poprzez przechwycenie zdarzenia Klawisz podglądu w dół z filtrowaniem wszystkich kluczy z wyjątkiem cyfrowych. Rozwiązanie to jest jednak bardziej skomplikowane, bo trzeba jeszcze zawracać sobie głowę stanem „podsumowania” TextBoxa, a czysto teoretycznie separatorem części całkowitej i ułamkowej może być nie jeden znak, a cały ciąg znaków (NumberFormatInfo.NumberDecimalSeparator zwroty strunowy, ale nie zwęglać).
W przypadku imprezy jest jeszcze jedna opcja klawisz w dół zapisz poprzedni stan Pole tekstowe.Tekst, a w razie Zmieniono tekst zwróć mu starą wartość, jeśli nowa wartość nie pasuje. Ale to rozwiązanie wygląda nienaturalnie i nie będzie tak łatwo je zaimplementować przy użyciu dołączonych właściwości.

Wniosek

Kiedy ostatnio rozmawialiśmy z kolegami o braku przydatnych i bardzo typowych funkcji w WPF, doszliśmy do wniosku, że jest na to wytłumaczenie i jest to pozytywna strona. Wyjaśnienie sprowadza się do tego, że od prawa nieszczelnych abstrakcji nie ma ucieczki, a WPF, będąc bardzo złożoną „abstrakcją”, płynie jak sito. Przydatną stroną jest to, że brak niektórych przydatnych funkcji sprawia, że ​​czasami myślimy (!) I nie zapominajmy, że jesteśmy programistami, a nie rzemieślnikami kopiuj-wklej.

Przypomnę, że pełną implementację klas powyższych klas, przykłady ich użycia oraz testy jednostkowe można znaleźć na githubie.

Tagi: Dodaj tagi

W tej instrukcji rozważymy wpisanie tylko liczb od użytkownika. W Microsoft Visual Studio jest kontrola " Maskowane pole tekstowe”, z konfigurowalną maską wprowadzania, ale zakładamy, że dzisiaj jesteśmy zainteresowani tylko« pole tekstowe».
Do realizacji tego zadania wykorzystamy zdarzenie „ naciśnięcie klawisza”, który występuje po naciśnięciu klawisza, gdy kontrolka ma fokus. Utwórz projekt forma okien w Microsoft Visual Studio i dodaj kontrolkę do głównego formularza pole tekstowe”. Wybierz ten komponent i kliknij go prawym przyciskiem myszy, wybierz z wyświetlonego menu kontekstowego element " Nieruchomościnaciśnięcie klawiszatextBox1_KeyPress", rozwój" naciśnięcie klawisza».
Z każdym wydarzeniem naciśnięcie klawisza» przekazany obiekt « KeyPressEventArgs”. Ten obiekt zawiera właściwość „ brelok” reprezentujący znak naciśniętego klawisza. Na przykład po naciśnięciu klawiszy SHIFT + D ta właściwość zwraca wielką literę D i jej kod 68. Istnieje również właściwość „ obsługiwane', który służy do określenia, czy zdarzenie zostało obsłużone. Ustawiając wartość " obsługiwane" w " PRAWDA", zdarzenie wejściowe nie zostanie wysłane system operacyjny do domyślnego przetwarzania.
Przyjrzyjmy się kilku przykładom tworzenia ograniczeń wprowadzania danych w polu tekstowym.
Przykład 1:
textBox1_KeyPress".

if ((e.KeyChar<= 47 || e.KeyChar >= 58) && e.KeyChar != 8) e.Handled = true; Ten przykład zawiera warunki złożone z operatorami logicznymi, takimi jak &&(oraz), || (lub), ! (nie) i sprawdza kod dziesiętny wprowadzonego znaku, zgodnie z dwoma warunkami:

  • "e.KeyChar != 8" - Jeśli naciśnięto klawisz "Backspace", zezwól na usuwanie znaków.
  • "(e.KeyChar<= 47 || e.KeyChar >= 58 )" — Jeśli wprowadzony znak ma kod ASCII mniejszy lub równy 47 i większy lub równy 58, wprowadzanie jest zabronione.
Poniżej jest Tabela kodów ASCII, w którym wyróżnione są na czerwono znaki, których wchodzenie jest zabronione oraz na zielono, których wchodzenie jest dozwolone.

Przykład 2:
Dodaj następujący wpis do „ textBox1_KeyPress».
if (!Char.IsDigit(e.KeyChar) && e.KeyChar != Convert.ToChar(8)) ( e.Handled = true; ) Ten przykład używa również operatorów logicznych, takich jak &&(oraz), ! (nie) i sprawdzany jest kod dziesiętny wprowadzonego znaku, zgodnie z dwoma warunkami. Metoda służy do sprawdzenia Znak.Is.Cyfra", który zwraca" PRAWDA„”, jeśli wprowadzony znak Unicode jest cyfrą dziesiętną, a „ fałszywy", Jeśli nie. Jest też czek na naciśnięcie klawisza " Backspace».
Przykład 3:
if (!(Char.IsDigit(e.KeyChar)) && !((e.KeyChar == ".") && (((TextBox)sender).Text.IndexOf(".") == -1) && ( ((TextBox)sender).Text.Length != 0))) ( if (e.KeyChar != (char)Keys.Back) ( e.Handled = true; )) W tym przykładzie, podobnie jak w poprzednim, kod znaku wejściowego sprawdzany jest za pomocą „ Znak.Is.Cyfra”, ale istnieje dodatkowy warunek, który pozwala na wprowadzenie jednego separator liczb dziesiętnych. W tym celu stosuje się metodę Text.IndexOf”. Ta metoda wyszukuje znak okresu za pomocą słów przy użyciu bieżącej kultury. Wyszukiwanie rozpoczyna się od pozycji pierwszego znaku w tym przypadku (bieżąca linia) i kontynuuje do pozycji ostatniego znaku. Jeżeli dany symbol nie został znaleziony, to metoda zwraca wartość „ -1 ”. Jeśli znak został znaleziony, metoda zwraca dziesiętną liczbę całkowitą wskazującą pozycję danego znaku i zabrania przetwarzania danych wejściowych znaku.

Separator liczb dziesiętnych- znak służący do oddzielenia części całkowitych i ułamkowych liczby rzeczywistej w postaci ułamka dziesiętnego w systemie dziesiętnym. W przypadku ułamków w innych systemach liczbowych można użyć terminu separator części całkowitej i ułamkowej liczby. Czasami można również używać terminów przecinek dziesiętny i przecinek dziesiętny. (http://ru.wikipedia.org).
Więcej informacji na temat metody Text.IndexOf» można uzyskać pod adresem: http://msdn.microsoft.com .

Przykład 4:
Dodaj następujący wpis do „ textBox1_KeyPress».

if (!System.Text.RegularExpressions.Regex.Match(e.KeyChar.ToString(), @"").Success) ( e.Handled = true; ) Aby sprawdzić znaki wejściowe, w tym przykładzie metoda „ Dopasowania wyrażeń regularnych”. Ta metoda przeszukuje ciąg wejściowy pod kątem wszystkich wystąpień danego wyrażenia regularnego. Wyrażenie regularne to wzorzec znaków reprezentujący sekwencję znaków o dowolnej długości. Możesz określić dowolne wyrażenie regularne, na przykład zezwalaj tylko na znaki „ ' lub zezwól na wprowadzenie separatora dziesiętnego ' ,|.| ».
Przykład 5:
Dodaj następujący wpis do „ textBox1_KeyPress».

if (!System.Text.RegularExpressions.Regex.IsMatch(e.KeyChar.ToString(),@"\d+")) e.Handled = true; W tym przykładzie użyto również podanego wyrażenia regularnego do zaimplementowania walidacji wprowadzonego znaku. Wyrażenie regularne używa „ + ”, co oznacza, że ​​można znaleźć jeden lub więcej znaków tego samego typu. Na przykład, \d+ pasuje do liczb „1”, „11”, „1234” itp. Jeśli nie jesteś pewien, jakie liczby będą następować po numerze? Możesz określić, że dozwolona jest dowolna liczba cyfr lub brak cyfr. W tym celu symbol „ * ».
Przykład 6:
Aby zaimplementować ten przykład, musisz użyć zdarzenia „ klawisz w dół", element sterujący" Pole tekstowe1”. Przejdź do głównego konstruktora formularza i wybierz komponent " Pole tekstowe1”. Kliknij prawym przyciskiem myszy tę kontrolkę, wybierz z wyświetlonego menu kontekstowego element " Nieruchomości”. W oknie, które się otworzy, przejdź do zdarzeń składowych (ikona błyskawicy w górnej części okna) i znajdź zdarzenie „ klawisz w dół”, kliknij dwukrotnie to wydarzenie. Po wykonaniu wszystkich kroków przejdziesz do automatycznie generowanej metody " TextBox1_KeyDown", rozwój" klawisz w dół”. To zdarzenie występuje przy każdym naciśnięciu klawisza, gdy kontrolka ma fokus.

Zdarzenia wejściowe z klawiatury

Gdy użytkownik naciśnie klawisz, uruchamiana jest seria zdarzeń. W tabeli wymieniono te zdarzenia w kolejności, w jakiej występują:

Chronologia występowania zdarzeń
Nazwa Typ routingu Opis
Klawisz podglądu w dół tunelowanie Występuje po naciśnięciu klawisza.
klawisz w dół rozprzestrzenianie się bąbelków Podobnie
Wprowadzanie tekstu podglądu tunelowanie Występuje po zakończeniu naciśnięcia klawisza, a element otrzyma dane wejściowe tekstowe. Zdarzenie to nie występuje w przypadku klawiszy, które nie „drukują” znaków (na przykład nie występuje po naciśnięciu klawiszy , , , klawisze kursora, klawisze funkcyjne itp.)
Wprowadzanie tekstu rozprzestrzenianie się bąbelków Podobnie
PreviewKeyUp tunelowanie Występuje po zwolnieniu klawisza
klawisz w górę rozprzestrzenianie się bąbelków Podobnie

Obsługa zdarzeń na klawiaturze wcale nie jest tak łatwa, jak mogłoby się wydawać. Niektóre kontrolki mogą blokować niektóre z tych zdarzeń w celu wykonania własnej obsługi klawiatury. Najbardziej godnym uwagi przykładem jest element TextBox, który blokuje zdarzenie TextInput oraz zdarzenie KeyDown w celu naciśnięcia niektórych klawiszy, takich jak klawisze kursora. W takich przypadkach zwykle można nadal używać zdarzeń tunelowanych (PreviewTextInput i PreviewKeyDown).

Element TextBox dodaje jedno nowe zdarzenie TextChanged. To zdarzenie jest uruchamiane natychmiast po naciśnięciu klawisza zmiany tekstu w polu tekstowym. Jednak w tym momencie nowy tekst jest już widoczny w polu tekstowym, więc jest już za późno na cofnięcie niechcianego naciśnięcia klawisza.

Obsługa naciśnięć klawiszy

Zrozumienie, jak działają i są używane zdarzenia klawiatury, najlepiej jest zilustrować na przykładzie. Poniżej znajduje się przykładowy program, który monitoruje i rejestruje wszystkie możliwe naciśnięcia klawiszy, gdy aktywne jest pole tekstowe. W takim przypadku wyświetlany jest wynik wpisania dużej litery S.

Ten przykład pokazuje jeden ważny punkt. Zdarzenia PreviewKeyDown i KeyDown są wywoływane przy każdym naciśnięciu klawisza. Jednak zdarzenie TextInput jest uruchamiane tylko wtedy, gdy znak został „wprowadzony” do elementu. W rzeczywistości może to oznaczać naciskanie wielu klawiszy. W tym przykładzie musisz nacisnąć dwa klawisze, aby uzyskać Wielka litera S: najpierw klucz , a następnie klawisz . Powoduje to powstanie dwóch zdarzeń KeyDown i KeyUp, ale tylko jednego zdarzenia TextInput.

Ignoruj ​​powtarzające się naciśnięcia znaków

Publiczna klasa częściowa MainWindow: Window ( public MainWindow() ( InitializeComponent(); ) private void Clear_Click(object sender, RoutedEventArgs e) ( lbxEvents.Items.Clear(); txtContent.Clear(); i = 0; ) protected int i = 0; private void KeyEvents(object sender, KeyEventArgs e) ( if ((bool)chkIgnoreRepeat.IsChecked && e.IsRepeat) return; i++; string s = "Event" + i + ": " + e.RoutedEvent + " Key : " + e.Key; lbxEvents.Items.Add(s); ) private void TextInputEvent(object sender, TextCompositionEventArgs e) ( i++; string s = "Zdarzenie" + i + ": " + e.RoutedEvent + " Klucz: " + e.Tekst; lbxEvents.Items.Add(s; ) )

Zdarzenia PreviewKeyDown, KeyDown, PreviewKeyi KeyUp przekazują te same informacje do obiektu KeyEventArgs. Najważniejszą częścią jest właściwość Key, która zwraca wartość z wyliczenia System.Windows.Input.Key i identyfikuje naciśnięty lub zwolniony klawisz.

Wartość klucza nie uwzględnia stanu żadnego innego klawisza - na przykład, czy klawisz został naciśnięty w momencie tłoczenia ; tak czy inaczej otrzymasz tę samą wartość klucza (Key.S).

Jest tu jedna trudność. W zależności od konfiguracji klawiatury w systemie Windows przytrzymanie klawisza powoduje ponowne naciśnięcie klawisza po krótkim czasie. Na przykład naciśnięcie klawisza spowoduje wpisanie w pole tekstowe serii znaków S. Podobnie naciśnięcie klawisza skutkuje powtarzającymi się kliknięciami i serią zdarzeń KeyDown. W prawdziwym przykładzie, naciskając kombinację pole tekstowe wygeneruje serię zdarzeń KeyDown dla klucza , a następnie zdarzenie KeyDown dla klawisza , zdarzenie TextInput (lub zdarzenie TextChanged w przypadku pole tekstowe), a następnie zdarzenie KeyUp dla kluczy oraz . Jeśli chcesz ignorować naciśnięcia klawiszy , możesz sprawdzić, czy naciśnięcie jest wynikiem naciśnięcia klawisza, przy użyciu właściwości KeyEventArgs.IsRepeat.

Zdarzenia PreviewKeyDown, KeyDown, PreviewKey i KeyUp są bardziej odpowiednie do pisania kodu niskiego poziomu do obsługi wprowadzania danych z klawiatury (co jest rzadko potrzebne, z wyjątkiem kontrolek użytkownika) i obsługi specjalnych naciśnięć klawiszy (takich jak klawisze funkcyjne).

Po zdarzeniu KeyDown następuje zdarzenie PreviewTextInput. (Zdarzenie TextInput nie jest zgłaszane, ponieważ blokuje je TextBox). W tym momencie tekst nie jest jeszcze wyświetlany w kontrolce.

Zdarzenie TextInput zapewnia kod obiektowy TextCompositionEventArgs. Ten obiekt zawiera właściwość Text, która zapewnia renderowany tekst gotowy do przekazania do kontrolki.

W idealnym przypadku zdarzenie PreviewTextInput może służyć do przeprowadzania walidacji kontrolek, takich jak TextBox. Na przykład, jeśli tworzysz pole tekstowe, które akceptuje tylko liczby, możesz sprawdzić, czy bieżące naciśnięcie klawisza wprowadziło literę i ustawić flagę Obsługiwane, jeśli tak. Niestety zdarzenie PreviewTextIlnput nie jest generowane dla niektórych kluczy, które muszą być obsługiwane. Na przykład naciśnięcie spacji w polu tekstowym całkowicie pomija zdarzenie PreviewTextInput. Oznacza to, że będziesz musiał również obsłużyć zdarzenie PreviewKeyDown.

Niestety, trudno jest zaimplementować niezawodną logikę walidacji danych w module obsługi zdarzeń PreviewKeyDown, ponieważ dostępna jest tylko wartość klucza i jest to informacja zbyt niskiego poziomu. Na przykład wyliczenie Key rozróżnia klawisze na klawiaturze numerycznej (blok do wprowadzania tylko cyfr) i zwykłą klawiaturę. Oznacza to, że w zależności od tego, gdzie zostanie naciśnięty klawisz 9, otrzymasz Key.D9 lub Key.NumPad9. Sprawdzanie wszystkich poprawnych wartości jest co najmniej bardzo żmudne.

Jednym wyjściem jest skorzystanie z klasy Konwerter kluczy, co pozwala przekonwertować wartość Key na bardziej przydatny ciąg. Na przykład wywołanie funkcji KeyConverter.ConvertToString() z dowolną wartością Key.D9 i Key.NumPad9, zwraca wynik ciągu „9”. Wywołanie konwersji Key.ToString() daje mniej użyteczną nazwę wyliczenia (albo „D9” lub „NumPad9”):

Konwerter KeyConverter = nowy KeyConverter(); ciąg klucz = konwerter.ConvertToString(e.Key);

Jednak używanie KeyConverter również nie jest zbyt wygodne, ponieważ musisz obsługiwać długie wiersze (na przykład "Backspace") dla tych naciśnięć klawiszy, które nie powodują wprowadzania tekstu.

Najbardziej odpowiednią opcją jest obsługa zdarzenia PreviewTextInput (gdzie wykonywana jest większość walidacji) w połączeniu ze zdarzeniem PreviewKeyDown dla naciśnięć klawiszy, które nie generują zdarzenia PreviewTextInput w polu tekstowym (takim jak spacja).



Wesprzyj projekt - udostępnij link, dzięki!
Przeczytaj także
zasady gry walki kogutów zasady gry walki kogutów Mod dla Minecraft 1.7 10 receptur zegarków.  Przepisy na tworzenie przedmiotów w Minecrafcie.  Broń w Minecraft Mod dla Minecraft 1.7 10 receptur zegarków. Przepisy na tworzenie przedmiotów w Minecrafcie. Broń w Minecraft Szyling i funt szterling - pochodzenie słów Szyling i funt szterling - pochodzenie słów