Hallo,
wie kann ich in einer WPF Anwendung in einer Textbox nur Zahlen zulassen?
In einer Windows Forms Anwendung habe ich das so gelöst:
public static void onlynum_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if (e.KeyChar != '\b' && e.KeyChar != ',')
//Copy & paste zulassen
if(Char.IsControl((e.KeyChar)))
{
}
//Nur Nummern zulassen
else if (!Char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
Hallo und willkommen bei myCSharp.de,
du musst auf das PreviewTextInput-Event reagieren und dann checken ob es eine Zahl ist.
Siehe dazu:
http://dotnetus.spaces.live.com/Blog/cns!4E39ECD492E4EEC1!550.entry
Gruss
Michael
Danke.
Funktioniert so.
Aber die Leerzeichen werden noch eingegeben.
Wie kann ich die Leerzeichen entfernen?
ähhhh, lass mich überlergen.....
.....
.....
Nach stundenlanger Überlegung bin ich zu der genialen Idee gekommen, dass du den Code, den dir michlG gepostet hat, wohl noch dahingehend erweitern musst, dass er zusätzlich prüft, ob du wohl ein Leerzeichen eingegeben hast.
Nach Stundenlangen versuchungen hab ich es nicht auf die Reihe bekommen. 🙂
Selbst wenn ich e.Handled immer auf true setze werden Leerzeichen trotzdem noch akzeptiert!?
ich hatte das vor langer zeit schon selber gebastelt:
IntegerTextBox
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Ast.CustomControls
{
public class IntegerTextBox : TextBox
{
public IntegerTextBox()
{
CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, null, CanPasteCommand));
}
public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register(
"MinValue",
typeof(int?),
typeof(IntegerTextBox));
public int? MinValue
{
get { return (int?)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
"MaxValue",
typeof(int?),
typeof(IntegerTextBox));
public int? MaxValue
{
get { return (int?)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
private bool Parse(TextBox box, string insertText)
{
string input = box.Text;
input = input.Remove(box.SelectionStart, box.SelectionLength);
input = input.Insert(box.SelectionStart, insertText);
if ((input.Equals("-", StringComparison.Ordinal)) &&
(MinValue == null || MinValue < 0))
return true;
else
{
int value = 0;
if (int.TryParse(input, System.Globalization.NumberStyles.Integer, CultureInfo.CurrentUICulture, out value) &&
IsValidRange(value))
return true;
else
return false;
}
}
private void CanPasteCommand(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = false;
if (Clipboard.ContainsText())
{
if (Parse(sender as TextBox, Clipboard.GetText()))
e.CanExecute = true;
}
e.Handled = true;
}
protected override void OnPreviewTextInput(TextCompositionEventArgs e)
{
if (Parse(this, e.Text))
base.OnPreviewTextInput(e);
else
e.Handled = true;
}
private bool IsValidRange(int value)
{
if ((MinValue == null || value >= MinValue) &&
(MaxValue == null || value <= MaxValue))
return true;
return false;
}
}
}
DoubleTextBox
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Ast.CustomControls
{
public class DoubleTextBox : TextBox
{
public DoubleTextBox()
{
CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, null, CanPasteCommand));
}
public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register(
"MinValue",
typeof(double?),
typeof(IntegerTextBox));
public double? MinValue
{
get { return (double?)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
"MaxValue",
typeof(double?),
typeof(IntegerTextBox));
public double? MaxValue
{
get { return (double?)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
private bool Parse(TextBox box, string insertText)
{
string input = box.Text;
input = input.Remove(box.SelectionStart, box.SelectionLength);
input = input.Insert(box.SelectionStart, insertText);
if ((input.Equals("-", StringComparison.Ordinal)) &&
(MinValue == null || MinValue < 0))
return true;
else
{
double value = 0;
if (double.TryParse(input, System.Globalization.NumberStyles.Float, CultureInfo.CurrentUICulture, out value) &&
IsValidRange(value))
return true;
else
return false;
}
}
private void CanPasteCommand(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = false;
if (Clipboard.ContainsText())
{
if (Parse(sender as TextBox, Clipboard.GetText()))
e.CanExecute = true;
}
e.Handled = true;
}
protected override void OnPreviewTextInput(TextCompositionEventArgs e)
{
if (Parse(this, e.Text))
base.OnPreviewTextInput(e);
else
e.Handled = true;
}
private bool IsValidRange(double value)
{
if ((MinValue == null || value >= MinValue) &&
(MaxValue == null || value <= MaxValue))
return true;
return false;
}
}
}
es gibt derzeit nur unstimmigkeiten wenn man text in der xaml direkt eingibt - es werden nur user eingaben abgefangen
auch wenn man eine minimum eingibt und eine zahl durch markieren loescht, dann kann man ausser paste die zahl nicht mehr eintippen - aber die probleme sind recht klein - ich persoenlich setz das minimum meist auf 0 usw - dann passiert nix
meine erste implementation hatte auch ein "Value" property - da war aber staendig das problem es mit "Text" in sync zu halten
wie dem auch sei
seit ich diese box habe, kann ich problemlos double.Parse und int.Parse ohne Try verwenden da ich weiss das nichts falsches rein kommen kann
Das Problem beim PreviewTextInput ist, dass die Leertaste keinen Event abfeuert.
Daher kannst Du das so einfach nicht über den Event abfangen. Hab' derzeit die gleiche Hürde.
Ich seh jetzt nicht wie Mr. Evil das Problem löst.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
das leertaste problem besteht auch - grad probiert
ist mir persoenlich noch nie aufgefallen #gg
TextBox's PreviewTextInput event does not trigger on spaces input
eine moeglichkeit waere beim parsen eines normalen textes die leerzeichen zu entfernen - bei integer oder double textbox sind leerzeichen eh humbug
(string.Trim)
Ich hab das Problem auf diesem Wege gelöst:
private void OnTextBox_Name_TextChanged( object sender, TextChangedEventArgs a_textArgs)
{
TextBox a_textBox = ( TextBox )sender;
if ( !Regex.IsMatch( a_textBox.Text, "^[a-zA-Z0-9-]+$" ) )
{
int a_charToRemove = ( (TextBox) ( ( ( RoutedEventArgs )( a_textArgs ) ).OriginalSource ) ).CaretIndex;
a_textBox.Text = a_textBox.Text.Remove( a_charToRemove -1 , 1 );
a_textBox.SelectionStart = a_textBox.Text.Length;
a_textArgs.Handled = true;
}
}
TextChanged wird IMMER aufgerufen - auch bei Sonder- und Leerzeichen.
Ich überprüfe zwar nicht auf Zahlen, sondern auf bestimmte Zeichen; das Prinzip ist aber das selbe.
Sobald der Text meine Vorgabe nicht entspricht wird durch den "CaretIndex" das Zeichen ermittelt, das sich geändert hat. Es muss also das Zeichen sein, das ungültig ist - schließlich war die Eingabe davor noch in Ordnung.
Dieses Zeichen entferne ich mit Remove() und setze das SelectionSymbol an das Ende der Eingabe - theoretisch kann man es auch an den CaretIndex setzen.
Was im Moment nicht abgefangen wird ist das Einfügen von Text!
😃
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Nun fängt es auch Mehrfangeingaben durch nen Paste ab:
private void OnTextBox_Name_TextChanged( object sender, TextChangedEventArgs a_textArgs )
{
TextBox a_textBox = ( TextBox )sender;
string a_newText = string.Empty;
for ( int i = 0; i < a_textBox.Text.Length; i++ )
{
if ( Regex.IsMatch( a_textBox.Text[ i ].ToString( ), "^[a-zA-Z0-9-]+$" ) )
{
a_newText += a_textBox.Text[ i ];
}
}
a_textBox.Text = a_newText;
a_textBox.SelectionStart = a_textBox.Text.Length;
}
Es geht bei jeder Eingabe jedes Zeichen durch.
Wenn ich das Zeichen einzeln herausziehe ist die Laufzeit höher, obwohl nur ein Zeichen überprüft wird.
Liegt wohl am Herausziehen durch den CaretIndex - wieso auch immer.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo,
normalerweise bindet man eine textbox auf eine Eigenschaft. Dies würde ich mir an dieser Stelle zu nutzen machen.
Ich hätte das so gemacht
<TextBox Text="{Binding Path=Prop,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
Und im Propertie prüfen, welchen value man erhält:
private string _Prop = String.Empty;
public string Prop
{
get
{
return _Prop;
}
set
{
//Mittels Regex / oder sonst einer prüfungsroutine prüfen ob wir nur zahlen haben
string inputString = value as string;
int inputNumber;
if (false == int.TryParse(value, out inputNumber))
{
_Prop = string.Empty;
}
else
{
_Prop = value;
}
}
Mittels Regex wär das schöner, angenommen der Benutzer gibt adg456asdf45.
Dann könnte man die vorhandenen Zahlen in die Propertie schreiben und die Buchstaben lässt man weg.
Mit dieser Variante benötigt man kein Event.
Vlt. sollte man an dieser Stelle auch noch IDataErrorInfo und ValidationsRules erwähnen, auch wenn sie das Thema nur bedingt streifen.
Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp
deine idee ist im prinzip kein eigenes control zu schreiben sondern das im property der viewmodel zu machen
nur wenn man so eine box sehr oft braucht muss man kopieren oder die methode sharen - da ist ein custom control besser
ich denke da an das beispiel von abt
man koennte mit seiner implementation die leerzeichen killen und dies dann in meine Integer oder DoubleTextBox packen - dann duerfte es vollstaendig sein #gg
Ich hab mir eine sehr einfache Lösung ausgedacht :
private void Textbox1_TextChanged(object sender, EventArgs e)
{
try
{
UInt16 Variable = Convert.ToUInt16(Textbox1.Text);
}
catch (FormatException)
{
Textbox1.Clear();
}
}
Beschreibung:
Das Programm versucht bei änderung der Eingabe den Text von String in UInt16 (kann auch Double usw. sein) zu konvertieren. Da Buchstaben (auch Leerzeichen) bei der Konvertierung eine FormatException auslösen, wird diese hier abgefangen und der Text in der Box wird gelöscht. In dem Catch Codeblock könnte auch eine Messagebox geöffnet werden oder sonst was.
Viel Spass damit 🙂
@robinator: Erstmal Danke. Die Exceptionlösung finde ich jedoch nicht so toll.
Die Exceptionlösung finde ich jedoch nicht so toll.
Da stimme ich zu. Exceptions sollten nicht genutzt werden, um den Programmfluß zu steuern. Besser wäre hier die Verwendung der UInt16.TryParse-Methode.
Christian
Weeks of programming can save you hours of planning
Man kann dies auch über ein Behavior lösen.
Basierend auf Stackoverflow einfach wie bereits hier im Thread erwähnt das PreviewEvent durch TextChanged austauschen und entsprechend behandeln.
Aussehen kann das TextChanged dann z.B. so:
void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
{
bool exceedsMaxLength = false;
var change = e.Changes.FirstOrDefault() as TextChange;
if (MaxLength > 0)
{
exceedsMaxLength = this.AssociatedObject.Text.Length > MaxLength;
}
if (!System.Text.RegularExpressions.Regex.IsMatch(this.AssociatedObject.Text, RegularExpression) || exceedsMaxLength)
{
var c = this.AssociatedObject.CaretIndex;
this.AssociatedObject.Text = this.AssociatedObject.Text.Remove(change.Offset, change.AddedLength);
this.AssociatedObject.CaretIndex = c -1;
}
}
Gruß
t0ms3n