Login Register
venerdì 10 febbraio 2012
 
Forums
I Forum di WPF Tips & Tricks
TextBox numerica (UserControl)
Last Post 02 ago 2010 10:00 by Alessandro Del Sole [MVP]. 7 Replies.
Printer Friendly
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages
Andrea Spaggiari
Basic Member
Basic Member
Posts:19
Avatar

--
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
Advanced Member
Posts:106
Avatar

--
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
Team
Posts:121
Avatar

--
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
Basic Member
Posts:19
Avatar

--
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
Advanced Member
Posts:106
Avatar

--
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
Basic Member
Posts:19
Avatar

--
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&#242; 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
Basic Member
Posts:19
Avatar

--
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
Team
Posts:121
Avatar

--
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
  
hd porn
 
© 2009-2011 WPF Tips&Tricks Team - Visual Basic Tips&Tricks Network
 
porno izleporno izle