+ Rispondi al messaggio
Pagina 1 di 2 12 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11

Alterare il dato immesso in una cella di DataGridView prima della validazione

  1. #1
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Di nuovo buongiorno.
    Avendo una DataGridView con una colonna collegata ad un campo di tipo DateTime, vorrei consentire all'utente di immettere una data senza digitare le barre, ma "normalizzando" - se possibile - l'input.
    All'uopo avrei una funzione banale di nome NormalizzaData che, se le cifre immesse possono essere interpretate come una data, restituisce una stringa nel formato dd/mm/yyyy.
    Il problema è che nell'evento CellValidating la verifica di validità avviene comunque su quanto effettivamente digitato dall'operatore e non sul risultato della normalizzazione, dando quindi un esito negativo con conseguente attivazione dell'evento DataError.
    If Not Date.TryParse(e.FormattedValue, dData) Then
         MessageBox.Show("Data non valida")
         e.Cancel = True
    EndIf
    
    Ho anche provato ad effettuare la normalizzazione negli eventi CellEndEdit, CellLeave, CellFormatting, CellParsing ma senza fortuna.
    A dire il vero ho anche provato la strada di ridefinire il tipo di colonna come DatePicker, ma ho trovato vari inconvenienti per me difficili da eliminare data la quantità di codice della classe che si trova facilmente come esempio.
    Qualche suggerimento?
    Ultima modifica di Brontolo; 06-03-2021 16:48 
    ℹ️ Leggi di più su Brontolo ...

  2. #2
    Hai provato impostando la defaultcellstyle.format ?
    ℹ️ Leggi di più su Fix ...

  3. #3
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Sì, ma non è sufficiente. Forse, tra tutti gli eventi citati, quello che ha più probabilità è CellParsing. Sto facendo delle prove.
    ℹ️ Leggi di più su Brontolo ...

  4. #4
    Ok, allora utilizza il TryParseExact con un formato specifico.

    Questo codice ad esempio convalida fintanto che si inserisce un valore nel formato "ddMMyyyy"

            Dim dt As DateTime
    
            If DataGridView1.Rows(e.RowIndex).IsNewRow Then Return
            If Not DateTime.TryParseExact(e.FormattedValue.ToString, "ddMMyyyy", New Globalization.CultureInfo("it-IT"), Globalization.DateTimeStyles.None, dt) Then
                Debug.WriteLine(e.FormattedValue.ToString)
                e.Cancel = True
            Else
                Debug.WriteLine(dt.ToString)
            End If
    
    Ultima modifica di Fix; 06-03-2021 18:51 
    ℹ️ Leggi di più su Fix ...

  5. #5
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Sì, funziona nel senso che la validazione non dà esito negativo, ma la data nel formato ddMMyyyy non può essere usata per una colonna collegata ad un campo DateTime. Occorre inserire le barre e questo non può essere fato su e.FormattedValue perché è ReadOnly. Può essere fatto su CurrenCell.Value

                   If Not DateTime.TryParseExact(e.FormattedValue.ToString, "ddMMyyyy", New Globalization.CultureInfo("it-IT"), Globalization.DateTimeStyles.None, dt) Then
                        Debug.WriteLine(e.FormattedValue.ToString)
                        e.Cancel = True
                    Else
                        dgvGrid.CurrentCell.Value = NormalData(e.FormattedValue)     '<===
                        Debug.WriteLine(dgvGrid.CurrentCell.Value.ToString)
                    End If
    
    ma non funziona e si accende l'evento DataError.

    Però sembra che il valore possa invece essere efficacemente modificato (dd/mm/yyyy) nell'evento CellParsing.
    Domani mattina a mente fresca penso che si risolverà.
    ℹ️ Leggi di più su Brontolo ...

  6. #6
    Scusa Brontolo ....

    Nell'evento "CellValidating" bisogna solo "validare" i dati, non modificare le celle.

    Sposta la modifica nell'evento "CellValidated", che viene generato subito dopo la convalida avvenuta su CellValidating

    Edit:
    Probabilmente puoi usare l’evento CellParsing ed hai ragione tu... serve la mente più fresca
    Ultima modifica di Fix; 06-03-2021 20:09 
    ℹ️ Leggi di più su Fix ...

  7. #7
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    In effetti così funziona. L'unico inconveniente è che la funzione NormalData, che cerca di inserire le barre nel posto giusto, va richiamata sia in CellValidating che in CellParsing. Posto il codice per intero, se qualcuno vuole migliorarlo...
       Private Sub dgvGrid_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles dgvGrid.CellValidating
            If Not dgvGrid.IsCurrentRowDirty Then Exit Sub
    
            Try
                Dim dData As Date
                If e.ColumnIndex = dgvGrid.Columns("Data").Index Then
                    Dim sData As String = NormalData(e.FormattedValue)
                    If sData <> "" AndAlso Not Date.TryParse(sData, dData) Then
                        MessageBox.Show("Data non valida")
                        e.Cancel = True
                    End If
                End If
    
            Catch ex As Exception
                MessageBox...
            End Try
        End Sub
    
        Private Sub dgvGrid_CellParsing(sender As Object, e As DataGridViewCellParsingEventArgs) Handles dgvGrid.CellParsing
            If Not dgvGrid.IsCurrentRowDirty Then Exit Sub
            If e.Value = "" Then Exit Sub
    
            Try
                Dim dData As Date
                If dgvGrid.Columns(e.ColumnIndex).Name = "Data" Then
                    If Date.TryParse(NormalData(e.Value.ToString), dData) Then
                        e.Value = dData
                        e.ParsingApplied = True
                    End If
                End If
    
            Catch ex As Exception
                MessageBox...
            End Try
        End Sub
    
        Private Function NormalData(sData As String) As String
            Try
                'Se non vengono digitate barre
                'tenta di interpretare al meglio la data
                If sData.IndexOf("/") = -1 Then
                    Select Case sData.Length
                        Case 8
                            sData = sData.Substring(0, 2) & "/" & sData.Substring(2, 2) & "/" & sData.Substring(4, 4)
                        Case 7
                            sData = sData.Substring(0, 1) & "/" & sData.Substring(1, 2) & "/" & sData.Substring(3, 4)
                        Case 6
                            sData = sData.Substring(0, 2) & "/" & sData.Substring(2, 2) & "/20" & sData.Substring(sData.Length - 2)
                        Case 5
                            sData = sData.Substring(0, 1) & "/" & sData.Substring(1, 2) & "/20" & sData.Substring(sData.Length - 2)
                        Case 4
                            sData = sData.Substring(0, 1) & "/0" & sData.Substring(1, 1) & "/20" & sData.Substring(sData.Length - 2)
                    End Select
                End If
                Return sData
    
            Catch ex As Exception
                Return sData
            End Try
        End Function
    
    Grazie Fix.
    ℹ️ Leggi di più su Brontolo ...

  8. #8
    Credo che il richiamo dipenda dal fatto che continui ad utilizzare il metodo TryParse senza specificare il formato o i formati che la stringa deve Matchare, per cui il metodo si aspetta un formato "standard" di Data.

    Se invece utilizzi il metodo TryParseExact, con l'overload String, String[], IFormatProvider, DateTimeStyles, DateTime, potrai verificare la stringa in base a diversi formati da te specificati e ricavare l'oggetto DATA/DATETIME senza necessità di usare la funzione. Nella guida (qui) c'è anche l'esempio di come comporre la lista di formati da usare per il match con la stringa.

    Se l'evento CellParsing viene generato DOPO l'evento CellValidating, potresti sfruttare il CellValidating per memorizzare l'oggetto DATA/DATETIME ricavato con il TryParseExact, quindi utilizzarlo nel CellParsing senza dover eseguire nuovamente la verifica della stringa. Ad esempio usando la proprietà TAG della cella per memorizzare l'oggetto DATA.
    ℹ️ Leggi di più su Fix ...

  9. #9
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Ho provato, ma non funziona
        Dim formats() As String = {"ddMMyyyy", "dMMyyyy", "ddMMyy", "dMMyy", "dMyy"}
                Dim sData As String = e.FormattedValue
                If sData <> "" AndAlso Not Date.TryParseExact(sData, formats,
                                                              New Globalization.CultureInfo("it-IT"),
                                                              Globalization.DateTimeStyles.None,
                                                              dData) Then
                    MessageBox.Show("Data non valida")
                    e.Cancel = True
                End If
    
    Intanto non vengono considerati validi i formati con il giorno di una cifra, tipo "dMMyy". E comunque rimane necessario chiamare la TryParseExact due volte.
    ℹ️ Leggi di più su Brontolo ...

  10. #10
    In effetti non funziona se il formato personalizzato con 1 d contempla solo numeri....

    Sembrerebbe una limitazione a livello di Framework, Microsoft indica questo:
    If you do not use date or time separators in a custom format pattern, use the invariant culture for the provider parameter and the widest form of each custom format specifier. For example, if you want to specify hours in the pattern, specify the wider form, "HH", instead of the narrower form, "H".
    Ovvero, che per formati personalizzati (senza separatori), bisogna utilizzare il formato ESTESO di ogni identificatore.

    Piuttosto che sbattermi a cercare di "normalizzare" un testo inserito da qualcun altro, cercherei di imporre l'inserimento nel formato che l'applicativo vuole (deciso da te o chi per te...)
    • O istruisci le persone ad inserire il dato come lo vuole il programma, pena: il campo non viene validato.
    • O lasci che sia generato l'errore (senza istruirlo), pena: il campo non viene validato.
    • O personalizzi colonna/cella estendendone il comportamento, aggiungendo una MaskedTextBox con la tua maschera di formato voluta (es: "##/##/####")

    Per le prime 2 opzioni, il codice è già pronto, il campo sarà validato se e solo se è nel formato con gli identificatori estesi "ddMMyyyy"

    Per la terza opzione bisogna scrivere del codice in più e fare degli approfondimenti.

    Procedura: Personalizzare celle e colonne nel controllo DataGridView di Windows Forms estendendone il comportamento e l'aspetto

    Esempio trovato in rete, che ho testato al volo e sembra funzionare, comunque merita un approfondimento sull'argomento, si tratta solo di uno spunto di partenza:

    MaskedDataGridView.txt
    ℹ️ Leggi di più su Fix ...

+ Rispondi al messaggio
Pagina 1 di 2 12 ultimoultimo

Potrebbero interessarti anche ...

  1. Validazione di una data in una cella di dataGridView
    Da Brontolo nel forum Visual Basic .Net
    Risposte: 2
    Ultimo Post: 06-03-2021, 16:15
  2. Risposte: 4
    Ultimo Post: 19-12-2012, 20:34
  3. Risposte: 14
    Ultimo Post: 10-08-2012, 08:35
  4. Risposte: 3
    Ultimo Post: 15-06-2010, 08:25
  5. problema con selezione della prima cella vuota excel vba
    Da omar70 nel forum Microsoft Excel
    Risposte: 10
    Ultimo Post: 19-05-2009, 17:44