Qualche giorno fa ho scritto un piccolo post per
cominciare a prendere in considerazione l'idea di poter avere diverse view di
una nostra custom collection. Giustamente, Corrado ha osservato che sebbene
avessi creato una classe FaultCollection ed una corrispondente
FaultCollectionDefaultView, c'è comunque un grande
accoppiamento fra le due. Una non vive senza l'altra e questo rende il mio
codice poco riutilizzabile: se voglio creare un'altra view, posso, però devo
ricompilare e così via. Insomma, volevo migliorare un po' le cose e questa sera
ho fatto i primi passi.
L'idea è innanzitutto quella di fornire alla classe
FaultCollection una classe gemella che fornisce le informazioni
sul binding. Questa classe non è più cablata in modo rigido nel codice, ma può
essere cambiata via codice in un secondo momento in base alle esigenze. La
classe FaultCollection espone quindi una proprietà
View di tipo ITypedList che per default è
FaultCollectionDefaultView.
public class FaultsCollection : BindingList<Fault>, ITypedList
{
private ITypedList _view = new FaultCollectionDefaultView();
public ITypedList View
{
get { return (_view); }
set { _view = value; }
}
#region ITypedList
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
return (_view.GetItemProperties(listAccessors));
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
return (_view.GetListName(listAccessors));
}
#endregion
}
Detto questo, ho creato una seconda classe che implementa
l'interfaccia ITypedList, chiamata
FaultCollectionPersistentView. La caratteristica di questa
classe è che permette di serializzare su file l'elenco delle proprietà, in modo
tale da mantenerle tra una sessione di lavoro e l'altra.
public class FaultCollectionPersistentView : ITypedList
{
private string[] _fieldNames = { "When", "Reason", "Gravity", "Consequence" };
private const String FILENAME = "DisplayCache.txt";
IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForAssembly();
}
La classe FaultCollectionPersistentView serializza sul file
DisplayCache.txt l'ordine delle proprietà mostrate dalla classe Fault su un
controllo DataGridView. L'ordine di default è quello indicato dalla variabile
privata _fieldNames. Il metodo GetItemProperties (necessario
per l'interfaccia ITypedList) questa volta è un po' più intelligente: se il file
DisplayCache.txt esiste, allora lo legge ed ordina le proprietà in base a
quello, altrimenti utilizza l'ordine di default indicato prima.
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
PropertyDescriptorCollection ret;
Type tp = typeof(Fault);
PropertyDescriptorCollection m_OriginalList = TypeDescriptor.GetProperties(tp);
if (isoFile.GetFileNames(FILENAME).Length == 0)
{
ret = m_OriginalList.Sort(_fieldNames);
saveColumnsOrder();
}
else
{
_fieldNames = loadColumnsOrder();
}
ret = m_OriginalList.Sort(_fieldNames);
ret.Remove(m_OriginalList.Find("ID", true));
return (ret);
}
La classe utilizza due metodi privati
saveColumnsOrder e loadColumnsOrder per,
rispettivamente, serializzare e deserializzare la variabile membro privata
_fieldNames. Giusto per pulizia o a scopi di debug, ho creato questo metodo
pubblico:
public void DeleteDisplayCache()
{
isoFile.DeleteFile(FILENAME);
}
che non fa altro che cancellare il file di cache che uso per salvare le
informazioni che mi servono.
Intercettare il reordering delle DataGridColumn di una
DataGridView
Passiamo a manipolare l'interfaccia utente. Quando
l'utente riordina a suo piacimento le colonne di una DataGridView, il framework
solleva l'evento ColumnDisplayIndexChanged che possiamo
intercettare e gestire a piacimento. Nel mio caso, quindi:
private void grdFaults_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
((FaultCollectionPersistentView)player.Faults.View).SaveColumnsOrder();
}
Queste è codice davvero brutto, brutto, brutto, che però ho scritto giusto
per fare debug e vedere che tutto funzionasse. In pratica, chiamo un metodo
pubblico SaveColumnsOrder che rileva il nuovo ordine delle
colonne e chiama successivamente il metodo privato
saveColumnsOrder descritto prima. Voglio assolutamente
migliorare questa cosa, perchè castare sempre e comunque a
FaultCollectionPersistentView è una follia, dato che abbiamo discusso prima il
fatto che potrei interscambiare le classi per poter avere diverse view di una
stessa custom collection.