Forms

3.69 Cambiare l'ordinamento di una casella di riepilogo a selezione multipla senza perdere le selezioni già effettuate
  Marco Pizzamiglio (namor)
(D)
E' possibile cambiare l'ordinamento di una casella di riepilogo (listbox) a selezione multipla senza perdere le selezioni già effettuate?

(R)
No, Access (almeno fino alla versione 2000) non prevede una simile opzione.
Quando si cambia l'origine dati di una listbox per modificarne l'ordinamento, le selezioni già effettuate vengono azzerate.
Per ottenere questo effetto bisogna procedere in questo modo:
1) Salvare le selezioni
2) Aggiornare l'origine dati della listbox
3) Riapplicare la selezione precedentemente salvata

Un modo semplicissimo per salvare le selezioni è mettere in una stringa le chiavi primarie dei record selezionati. L'esempio allegato lavora su una tabella 'Anagrafica' con chiave primaria a doppio campo numerico: 'IDGruppo' e 'IDPersonaggio'.

Al momento del salvataggio un ciclo scorre tutti i record della listbox e salva in una stringa ciascuna coppia 'IDGruppo' e 'IDPersonaggio' per i record selezionati. I due valori vengono separati da un carattere (in questo caso il '-') e le varie coppie di chiavi vengono separate da un altro carattere (in questo caso il '#').

Supponendo di aver selezionato nella listbox i record con codici
1 5
1 8
1 14
2 7
2 18
3 15
la stringa risultante sarà "#1-5#1-8#1-14#2-7#2-18#3-15#", e verrà salvata in una variabile.

A questo punto si modifica l'origine dati della listbox per variarne l'ordinamento o applicare eventuali filtri, il che azzera tutte le selezioni effettuate, e poi con un altro ciclo si scorre di nuovo tutta la listbox controllando per ciascun record se la chiave primaria è contenuta nella stringa salvata, nel qual caso si seleziona il record.
Per verificare se la chiave di un record (per esempio "#1-14#") è compresa nella lista si usa la funzione Instr(), che restituirà zero se la chiave NON è compresa nella lista o un valore maggiore di zero se lo è.
Il tutto è molto veloce, e se la listbox non contiene tantissimi record non ci si accorge del fatto che vengono prima deselezionati e poi riselezionati.

Negli esempi allegati, tralasciando le richieste di conferme, la gestione di eventuali incongruenze e la parte di salvataggio delle selezioni in tabella, le tre procedure che costituiscono il nocciolo del progetto sono:
- Ordina_lista_AfterUpdate
- ottieniSelezione
- applicaSelezione
che implementano quanto descritto sopra, sono corte e molto semplici, adatte per essere studiate anche dai principianti.

Le stringhe di selezione così generate possono anche essere facilmente salvate in una tabella per essere richiamate all'occorrenza.
L'esempio allegato contiene una nutrita tabella di personaggi disney ('Anagrafica'), una tabella in cui vengono salvate le selezioni ('Selezioni') e una maschera con la listbox che elenca i personaggi, dà la possibilità di variare l'ordinamento, applicare un filtro, salvare in tabella le selezioni effettuate e poi richiamarle.


NB:
Come separatori, in caso di chiavi con campi di tipo testo, bisogna usare caratteri che sicuramente non siano presenti nei campi che compongono la chiave primaria, altrimenti la procedura di riapplicazione delle selezioni potrebbe selezionare più record del dovuto.
Si pensi al caso:
A 1-B
A-1 B
Selezionando solo il primo record, con i separatori '-' e '#' la chiave sarà "#A-1-B#".
In fase di riapplicazione della selezione anche il secondo record genererà la stessa chiave e verrà quindi erroneamente selezionato.

PS
Ho riscontrato un bug nel conteggio degli elementi selezionati:
usando il tasto TUTTI che scorre con un ciclo For la listbox e seleziona tutti gli elementi, e poi il tasto NESSUNO che li deseleziona tutti, la proprietà ItemsSelected.Count della listbox risulta essere 1 anzichè zero, sebbene non sia selezionato alcun record.
Ciò è legato alla proprietà Intestazioni colonne della listbox: impostandola a Si Access97 e 2000 includono nel conteggio dei record selezionati anche la riga di intestazione. Per questo motivo negli esempi ho impostato a No tale proprietà e ho sostituito la riga di intestazione con delle etichette poste subito sopra la listbox. In questo modo in Access 2000 il problema si risolve, mentre in Access 97 persiste.

Download:
 
  ListBox.zip (56Kb) MSAccess97/2000 database


Se pensate di avere del materiale freeware interessante e volete pubblicarlo, allora leggete qui.