+ Rispondi al messaggio
Visualizzazione dei risultati da 1 a 8 su 8

DataGridView - Filtrare una colonna ComboBox in base ad un'altra

  1. #1
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Buongiorno.
    Supponiamo di avere una DataGridView con due colonne, entrambe ti tipo ComboBox (DataGridViewComboBoxColumn): la prima elenca le regioni italiane ed è popolata da una DataTable (tRegioni)

    col = New DataGridViewComboBoxColumn
    With col
           .Name = "Regione"
           .DataPropertyName = "IdRegione"
           .DataSource = tRegioni
           .ValueMember = "IdRegione
           .DisplayMember = "NomeRegione"
           .HeaderText = "REGIONE"
    End With
    dgv.Columns.Add(col)
    
    La seconda dovrebbe essere popolata con le province appartenenti alla regione della colonna precedente
    col = New DataGridViewComboBoxColumn
    With col
           .Name = "Provincia"
           .DataPropertyName = "IdPprovincia"
           .DataSource = tProvince
           .ValueMember = "IdProvincia"
           .DisplayMember = "DescrProvincia"
           .HeaderText = "PROVINCIA"
    End With
    dgv.Columns.Add(col)
    
    In pratica, in righe diverse in cui la regione è diversa, vorrei che l'insieme delle province disponibili nella seconda colonna fosse diverso e, in caso di modifica della regione nella prima colonna cambiassero "al volo" le province disponibili nella seconda.

    Nell'evento EditingControlShowing della dgv posso "estrarre" il ComboBox dalla prima colonna e assegnargli un gestore di evento
    If dgv.CurrentCell.ColumnIndex = 0 Then
         Dim combo As ComboBox = CType(e.Control, ComboBox)
         RemoveHandler combo.SelectedIndexChanged, AddressOf ComboBox_SelectedIndexChanged
         AddHandler combo.SelectedIndexChanged, AddressOf ComboBox_SelectedIndexChanged
    End If
    
    ma l'evento ComboBox_SelectedIndexChanged, nel quale vorrei popolare opportunamente la seconda colonna si verifica per entrambe le colonne. Come posso evitarlo per la seconda colonna?
    E poi, è corretto reimpostare la proprietà DataSource per ottenere il risultato voluto, visto che questa proprietà si applica all'intera colonna?
    ℹ️ Leggi di più su Brontolo ...

  2. #2
    Ciao Brontolo,
    probabilmente esiste qualche soluzione migliore di quella che sto per proporti, però ti metto un pò di carne al fuoco.

    Basandomi sul codice di esempio che hai postato, ho creato 2 Tabelle (Regioni e Province) con alcuni elementi, usando semplicemente 2 Campi per Regioni (IdRegione e Nome) e 3 Campi per le Province (Id, Nome, IdRegione)

    Ho creato quindi 2 DataTable denominati tRegioni e tProvince, da utilizzare per associare gli elementi alle 2 ComboBox, ed una DataGridView denominata dgv1

    All'interno di un evento Button_Click ho inserito il seguente codice, senza associazione dati per la colonna Province:
            Dim Col As New DataGridViewComboBoxColumn
            With Col
                .Name = "Regione"
                .DataSource = tRegioni
                .DisplayMember = "Nome"
                .ValueMember = "IdRegione"
                .HeaderText = "REGIONE"
            End With
            dgv1.Columns.Add(Col)
    
            Col = New DataGridViewComboBoxColumn
            With Col
                .Name = "Province"
                .DisplayMember = "Nome"
                .ValueMember = "Id"
                .HeaderText = "PROVINCE"
            End With
            dgv1.Columns.Add(Col)
    


    Poi, come da indicazioni Microsoft, ho agganciato l'evento ComboBox_SelectedIndexChanged
        Private Sub dataGridView1_EditingControlShowing(ByVal sender As Object,
        ByVal e As DataGridViewEditingControlShowingEventArgs) _
        Handles dgv1.EditingControlShowing
    
            If dgv1.CurrentCell.ColumnIndex = 0 Then
                Dim combo As ComboBox = CType(e.Control, ComboBox)
                If (combo IsNot Nothing) Then
                    RemoveHandler combo.SelectedIndexChanged, New EventHandler(AddressOf ComboBox_SelectedIndexChanged)
                    AddHandler combo.SelectedIndexChanged, New EventHandler(AddressOf ComboBox_SelectedIndexChanged)
                End If
            End If
        End Sub
    


    All'interno della ComboBox_SelectedIndexChanged ho usato una Query Linq, per creare un nuovo DataView da associare al DataSource dei controlli DataGridViewComboBoxCell appartenenti alle Province, in questo modo ogni Controllo avrà il suo Set di elementi disponibili in funzione dell'IdRegione
        Private Sub ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs)
    
            If dgv1.CurrentCell.ColumnIndex = 0 Then
                Dim cbRegioni As ComboBox = CType(sender, ComboBox)
                Dim cbProvince As DataGridViewComboBoxCell = CType(dgv1.CurrentRow.Cells(1), DataGridViewComboBoxCell)
    
                If (cbRegioni.SelectedValue Is Nothing) OrElse (cbRegioni.SelectedValue.GetType Is GetType(DataRowView)) Then Exit Sub
    
                Dim IdRegione As Integer = Convert.ToInt32(cbRegioni.SelectedValue)
    
                Dim qProvince = From dr In tProvince.AsEnumerable
                                Where dr.Field(Of Integer)("IdRegione") = IdRegione
                                Select dr
    
                cbProvince.DataSource = qProvince.AsDataView
    
            End If
    
        End Sub
    
    Vedi se può tornarti utile.
    ℹ️ Leggi di più su Fix ...

  3. #3
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Buongiorno Fix e grazie per i tuoi come sempre preziosi suggerimenti.
    La strada che mi indichi sembra proprio essere quella buona e anch'io stavo andando in una direzione simile dopo molti tentativi.
    Devo premettere che l'esempio basato su regioni e province è una metafora che mi è servita per semplificare l'esposizione del problema. In realtà l'oggetto delle colonne della griglia è altro e la situazione è un po' più complessa; per esempio le colonne combobox sono in realtà tre.
    Detto ciò, rispetto alla tua soluzione, sostituirei la creazione delle DataView tramite Linq con la creazione di tante DataTable quanti sono i valori presenti nella prima combobox, e questo per almeno due motivi:
    Il primo è che non ho al momento sufficiente pratica con le query Linq (prometto che rimedierò) ed ho quindi difficoltà ad adattarla alla situazione reale. Il secondo è che i valori possibili della prima combo sono al massimo quattro.
    L'idea quindi è quella di creare all'inizio le diverse DataTable da usare come DataSource, con un nome significativo aiutandomi con un Dictionary di poche elementi.
    Devo poi fare in modo che il popolamento della seconda combobox avvenga anche in fase di caricamento e non solo al SelectedIndexChanged e altre complicanze.
    Comunque di nuovo grazie. Tornerò al bisogno.
    ℹ️ Leggi di più su Brontolo ...

  4. #4
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Continuo a lavorarci su. Non capisco perché l'evento delegato ComboBox_SelectedIndexChanged si verifica anche per il combobox delle province nonostante la prima riga sembrerebbe limitarlo al combobox delle regioni
    Private Sub ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs)
         If dgv1.CurrentCell.ColumnIndex = 0 Then
            Dim cbRegioni As ComboBox = CType(sender, ComboBox)
            Dim cbProvince As DataGridViewComboBoxCell = CType(dgv1.CurrentRow.Cells(1), DataGridViewComboBoxCell)
     
            If (cbRegioni.SelectedValue Is Nothing) OrElse (cbRegioni.SelectedValue.GetType Is GetType(DataRowView)) Then Exit Sub
     
            Dim IdRegione As Integer = Convert.ToInt32(cbRegioni.SelectedValue)
     
            Dim qProvince = From dr In tProvince.AsEnumerable
                            Where dr.Field(Of Integer)("IdRegione") = IdRegione
                            Select dr
     
            cbProvince.DataSource = qProvince.AsDataView
     
        End If
     
    End Sub
    
    ℹ️ Leggi di più su Brontolo ...

  5. #5
    Non ho capito se intendi che si verifica e basta, oppure che viene eseguito anche il codice all'interno dell'IF ?

    Se si verifica la seconda condizione, è strano sì... Perchè un "ColumnIndex = 1" non può mai essere validata da quella IF

    Prova a verificare, all'interno della IF, il valore della proprietà Text del ComboBox
                Dim cbRegioni As ComboBox = CType(sender, ComboBox)
                Dim cbProvince As DataGridViewComboBoxCell = CType(dgv1.CurrentRow.Cells(1), DataGridViewComboBoxCell)
    
                If (cbRegioni.SelectedValue Is Nothing) OrElse (cbRegioni.SelectedValue.GetType Is GetType(DataRowView)) Then Exit Sub
    
                Debug.WriteLine(cbRegioni.Text)
                .....
    
    Dovrebbe mostrarti solo i nomi di Regione.

    ------------------

    Edit-Aggiunta:
    Per risolvere il problema della ri-generazione dell'evento, causato a quanto pare ad un problema di associazione dati e DisplayMember tardiva (rispetto al cambio dell'indice che si verifica prima), è possibile risolvere gestendo l'evento SelectionChangeCommitted al posto di SelectedIndexChanged, che si verifica solo DOPO che la modifica viene visualizzata nella ComboBox.

    La firma dell'evento è la stessa e si può rimuovere la verifica del Type DataRowView perchè il SelectedValue sarà sicuramente valorizzato correttamente quando sarà generato l'evento.
    Ultima modifica di Fix; 21-04-2021 19:42 
    ℹ️ Leggi di più su Fix ...

  6. #6
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Si verifica e basta. Con SelectedIndexChanged si verifica già quando si clicca sulla freccina del combobox province, mentre con SelectionChangeCommitted si verifica quando effettivamente si seleziona una provincia. Comunque la "If ColumnIndex = 1" ovviamente funziona e limita l'evento a questa colonna. Quindi pazienza anche se non capisco perché.

    Ora però dovrei collegare la griglia alla tabella di database sottostante, nella quale ogni record contiene, oltre ad altri campi che qui possiamo ignorare, il codice (Id) della provincia. Per far questo credo che dovrò aggiungere una colonna (anche invisibile) collegata a questo codice. Vediamo un po'.
    ℹ️ Leggi di più su Brontolo ...

  7. #7
    Spero di non dire una castroneria...

    Suppongo che l'evento sia generato su tutte le ComboBox, a prescindere dall'indice della ComboBox su cui viene agganciato, perchè viene associato al controllo PADRE ComboBox, da cui derivano poi tutte le nuove DataGridViewComboBoxEditingControl presenti nella griglia.

    L'oggetto DataGridViewComboBoxEditingControl non dispone di questi eventi, per cui si è obbligati a gestire quelli del controllo Padre.

    Questa è una spiegazione che mi sono dato ma potrebbe non essere corretta.
    ℹ️ Leggi di più su Fix ...

  8. #8
    L'avatar di Brontolo
    Brontolo non è in linea Very Important Person
    Mi sembra plausibile. Comunque, una volta che lo si sa, si rimedia facilmente.
    ℹ️ Leggi di più su Brontolo ...

+ Rispondi al messaggio

Potrebbero interessarti anche ...

  1. Risposte: 3
    Ultimo Post: 05-12-2019, 17:18
  2. Filtrare combobox in base a data
    Da SILVIO nel forum Microsoft Access
    Risposte: 2
    Ultimo Post: 25-02-2018, 20:01
  3. Risolto: Procedimento per filtrare i dati di una datagridview sulla base di una textbox.
    Da moneyscent nel forum Visual Basic .Net
    Risposte: 5
    Ultimo Post: 27-09-2011, 20:53
  4. [Excel] Filtrare da Fg1 a Fg2 in base a 1 colonna
    Da Zoro76 nel forum Microsoft Excel
    Risposte: 6
    Ultimo Post: 18-11-2010, 18:00
  5. [C# Datagridview] Colonna Combobox
    Da kenshin nel forum C#
    Risposte: 6
    Ultimo Post: 22-12-2008, 18:54