 |
|
I Forum di WPF Tips & Tricks
|
|
|
 |
|
 |
 |
 |
 |
|
TextBox numerica (UserControl)
Last Post 02 ago 2010 10:00 by Alessandro Del Sole [MVP]. 7 Replies.
|
Sort:
|
|
Prev Next |
You are not authorized to post a reply. |
|
Andrea Spaggiari
 Basic Member Posts:19

 |
| 31 lug 2010 11:10 |
|
Ciao a tutti, sto iniziando a creare qualche UserControl da riutilizzare nelle mie future applicazioni ed il mio primo controllo è una TextBox dove si potranno immettere solo numeri, positivi e negativi, interi o decimali, a seconda delle proprietà impostate. Il codice è il seguente: QUESTE SONO LE 2 PROPRIETA' Private _onlyPositive As Boolean Public Property OnlyPositive As Boolean Get Return _onlyPositive End Get Set(ByVal value As Boolean) _onlyPositive = value End Set End Property Private _onlyInteger As Boolean Public Property OnlyInteger As Boolean Get Return _onlyInteger End Get Set(ByVal value As Boolean) _onlyInteger = value End Set End Property SELEZIONO TUTTO IL TESTO ALL'EVENTO GOT FOCUS Private Sub txt_GotFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles txt.GotFocus txt.SelectAll() End Sub ELIMINIO LA POSSIBILITA' DI INSERIRE SPAZI Private Sub txt_PreviewKeyDown(ByVal sender As Object, ByVal e As System.Windows.Input.KeyEventArgs) Handles txt.PreviewKeyDown If e.Key = Key.Space Then e.Handled = True End If End Sub ...ed ora iniziano i problemi.. Per consentire all'utente di immettere solo numeri con o senza virgola, maggiori o minori di 0, ho provato varie strade, ma senza risultato, come ad esempio: Private Sub txt_TextChanged(ByVal sender As Object, ByVal e As System.Windows.Controls.TextChangedEventArgs) Handles txt.TextChanged If OnlyPositive Then If OnlyInteger Then If Not Integer.Parse(txt.Text) Then MsgBox("non intero e positivo") Else If txt.Text * -1 >= 0 Then MsgBox("negativo") End If Else If OnlyInteger Then If Not Long.Parse(txt.Text) Then MsgBox("non intero") End If End If End Sub Ho pensato anche all'evento LOST FOCUS, ma non mi piace molto perchè sa l'utente, ad esempio, clicca un pulsante, il risultato non è quello desiderato. Qualcuno saprebbe indirizzarmi sulla giusta strada? Ho provato anche con PREVIEW TEXT INPUT o TEXT INPUT... Inoltre, cercando su internet, tutti gli esempi trovati, sia in vb che in c# parlano di KEY PRESS, ma tra gli eventi della textbox in vs 2010 non ho trovato KEY PRESS.... |
|
|
|
|
Gianni Giaccaglini
 Advanced Member Posts:106

 |
| 02 ago 2010 10:30 |
|
Molto interessante. Forse sei incappato in qualche insidia sintattica. Suggerirei di partire con un esempio spicciolo per poi procedere, bottom-up, al caso del controllo personale. Comincio col suggerire una sintassi più consona a WPF, ovvero definendo i due eventi direttamente nella tag: <TextBox Margin="0,2,2,10" Name="miaCasella" Text="Scrivi qui" Height="25" Width="335" GotFocus="SelezionaTutto" TextChanged="SoloCifre"/> Ed ecco le due routine d'evento: Private Sub SelezionaTutto(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) MsgBox(sender.ToString & vbLf & e.OriginalSource.ToString) With miaCasella .SelectAll() If Not IsNumeric(.Text) Then .Text = "" End With End Sub Private Sub SoloCifre(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) With miaCasella Dim Lung = .Text.Length If Lung > 0 Then If Not IsNumeric(.Text) Then '.Text = "" 'Cura troppo drastica! .Text = .Text.Substring(1, Lung - 1) End If End If End With End Sub Entrambe utilizzano IsNumeric, la prima per cassare la scritta iniziale "Scrivi qui", mentre la seconda accetta anche UN SOLO carattere "," e/o ".". Per pigrizia trascuro il problema di acuisire la stringa immessa. Comunque penso di aver fornito spunti sia al nostro amico sia per un dibattito più ampio sul tema. |
|
|
|
|
Alessandro Del Sole [MVP]
 Team Posts:121

 |
| 02 ago 2010 11:57 |
|
Ti dò uno spunto diverso. A parte che per verificare se un carattere è numerico o meno ti basta usare il metodo Char.IsDigit, in WPF esiste un modo molto più elegante che è quello delle regole di validazione. Puoi creare un ErrorTemplate che "adorni" il tuo controllo con un colore diverso (ma è solo un esempio) fin tanto che l'utente immette valori indesiderati. Quindi, per quanto riguarda la validazione dell'immissione puoi usare Char.IsDigit. Poi implementi l'interfaccia IDataErrorInfo e mostri il risultato della validazione tramite ErrorTemplate. In questo mio post c'è un esempio, legato ad altro contesto: http://community.visual-basic.it/al...29774.aspx Ti può anche essere utile un post di Beth Massi: http://blogs.msdn.com/b/bethmassi/a...n-wpf.aspx Ovviamente sono solo spunti inerenti alcune caratteristiche peculiari di WPF, nulla di obbligatorio, sia chiaro. P.s.: Non c'è infatti KeyPress, ma puoi usare KeyUp. |
|
|
|
|
Andrea Spaggiari
 Basic Member Posts:19

 |
| 02 ago 2010 01:03 |
|
Intanto razie sia a Gianni che ad Alessandro per le idee, penso che oterò per la validazione, che ho già iniziato a studiare, grazie ai post di AlessaMa ndro (ndr. mi è da poco arrivato il tuo libro VB 2010 Unleashed...) ma non pensavo si potesse fare anche con una semplice textbox non collegata in binding... Ma l'implementazione dell'interfaccia IDataErrorInfo devo inserirla direttamente nella classe della TextBox? (m_validationErrors, AddError, RemoveError, HasError, [Error], Item e la proprietà Text da validare?) |
|
|
|
|
Gianni Giaccaglini
 Advanced Member Posts:106

 |
| 02 ago 2010 02:39 |
|
M'inchino alla sapienza! Una piccolissima osservazione: la sostituzione, del mio pur rude If Not IsNumeric(.Text) Then con If Not Char.IsDigit(.Text(Lung - 1)) Then ceteris paribus, accetta solo cifre, mentre la precedente non si ribella dinanzi ad UNA SOLA virgola o punto. Comunque il rimedio è presto trovato con un'espressione booleana Or & C. opportuna. Piuttosto un commento eretico. Le potenzialità mostrate da Alessandro sono impressionanti ma mi chiedo se questi orizzontin non rischino di richiedere una marea di codice - e conseguenti crescita dei costi di sviluppo. Nei casi normali della vita, non sarebbe più semplice che Ma' Microsoft fornisse un evento, come dire?, "più complessivo", scatenantesi quando l'utente completa l'input? Faccio il caso del pur spartano evento Change del VBA di Excel: Private Sub Worksheet_Change(ByVal Target As Range) If Target = Range("A1") Then If Not IsNumeric(ActiveCell) Then MsgBox "Valore numerico!" ActiveCell.Clear End If End If End Sub Al momento me ne sfugge l'equivalente in VB (LostFocus, immagino...), posso solo testimoniare che sviluppatori anche semi-pro per casi del genere si arrangiano con un pulsantino a fianco della TextBox, atto a convalidare o meno l'input dell'utente... |
|
|
|
|
Andrea Spaggiari
 Basic Member Posts:19

 |
| 02 ago 2010 06:53 |
|
In effetti, per la validazione dei dati, il codice da scrivere è abbbastanza, ho fatto alcune prove modificando il codice dei post sopracitati (che stavo già esaminando per il databinding) ma senza successo (purtroppo sono un appassionato che cerca di imparare, ma senza le basi purtroppo). Questo è un esempio d codice:
Public Class spTextBox
Implements IDataErrorInfo
Private validationErrors As New Dictionary(Of String, String)
Protected Sub AddError(ByVal columnName As String, ByVal msg As String)
If Not validationErrors.ContainsKey(columnName) Then
validationErrors.Add(columnName, msg)
End If
End Sub
Protected Sub RemoveError(ByVal columnName As String)
If validationErrors.ContainsKey(columnName) Then
validationErrors.Remove(columnName)
End If
End Sub
Public Overridable ReadOnly Property HasErrors() As Boolean
Get
Return (validationErrors.Count > 0)
End Get
End Property
Public ReadOnly Property [Error]() As String _
Implements System.ComponentModel.IDataErrorInfo.Error
Get
If validationErrors.Count > 0 Then
Return String.Format("{0} data is invalid.", TypeName(Me))
Else
Return Nothing
End If
End Get
End Property
Default Public ReadOnly Property Item(ByVal columnName As String) As String _
Implements System.ComponentModel.IDataErrorInfo.Item
Get
If validationErrors.ContainsKey(columnName) Then
Return validationErrors(columnName).ToString
Else
Return Nothing
End If
End Get
End Property
Private Sub OnTextChanging(ByVal value As String)
Me.CheckText(txt.Text)
End Sub
Private Sub CheckText(ByVal value As String)
value = txt.Text
If value = "" Then
Me.AddError("Text", "La casella di testo non può essere vuota")
Else
Me.RemoveError("Text")
End If
End Sub
Public Property Text As String
Get
Return txt.Text
End Get
Set(ByVal value As String)
txt.Text = value
End Set
End Property
Public Property TextAlignment As System.Windows.TextAlignment
Get
Return txt.TextAlignment
End Get
Set(ByVal value As System.Windows.TextAlignment)
txt.TextAlignment = TextAlignment
End Set
End Property
Private Sub txt_GotFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles txt.GotFocus
txt.SelectAll()
End Sub
End Class
E nello user control:
<TextBox Name="txt" BorderBrush="Black" HorizontalContentAlignment="Left" VerticalContentAlignment="Center"
Text="{Binding Path=Text, ValidatesOnDataErrors=True}">
<TextBox.Style>
<Style>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Control.ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
<Trigger Property="Control.IsFocused" Value="True">
<Setter Property="Control.Background" Value="Yellow"/>
<Setter Property="Control.FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox> |
|
|
|
|
Andrea Spaggiari
 Basic Member Posts:19

 |
| 02 ago 2010 09:38 |
|
Leggendo WPF4 Unleashed (ebbene ho comprato pure quello.... il materiale non mi manca.... il tempo per leggerli bene sì.... sigh...) ho trovato la VALIDATION RULE e, facendo qualche prova, il risultato è decente (ottimo per le mie conoscenze)... Riporto il codice:
<TextBox Name="txt" BorderBrush="Black" HorizontalContentAlignment="Left" VerticalContentAlignment="Center">
<TextBox.Text>
<Binding Path="Text" ElementName="txt" ValidatesOnDataErrors="True" ValidatesOnExceptions="True">
<Binding.ValidationRules>
<local:TextBoxValidationRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
<TextBox.Style>
<Style>
<Style.Triggers>
<Trigger Property="Control.IsFocused" Value="True">
<Setter Property="Control.Background" Value="Yellow"/>
<Setter Property="Control.FontWeight" Value="Bold"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Control.Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Public Class TextBoxValidationRule
Inherits ValidationRule
Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As System.Globalization.CultureInfo) As System.Windows.Controls.ValidationResult
Dim testo As String = value.ToString
If value = String.Empty Then
Return New ValidationResult(False, "Stringa vuota!")
End If
Return New ValidationResult(True, DBNull.Value)
End Function
End Class Il tutto funziona (ho messo solo il controllo di stringa vuota perchè è solo una prova) ma non riesco a far funionare l'implementazione dell' IDataErrorInfo... E' possibile utilizzare anche solo le Validation Rules in quel modo, o l'IDataErrorInfo sono più performanti, in caso di binding con varie sorgenti? (sto leggendo con interesse i post di Alessandro sul MVVM anche se sono ancora molto impegnativi per me, ma arriverò a capire anche quelli... spero...) |
|
|
|
|
Alessandro Del Sole [MVP]
 Team Posts:121

 |
| 02 ago 2010 10:00 |
|
Come in ogni cosa, non ci sono obblighi nè implementazioni perfette. Se quella da te costruita soddisfa i tuoi requisiti, va bene così. IDataErrorInfo è riconosciuta dai controlli WPF e quindi facilita la validazione soprattutto in data-binding, ma non devi per forza usarla nè saprei dirti cosa sia più performante. Siccome so che sei volenteroso, ho voluto darti qualche spunto a studiare qualcosa di nuovo  |
|
|
|
|
| You are not authorized to post a reply. |
|
Active Forums 4.2
|
|
|
 |
 |
 |
 |
|
|