Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

Una 'default view' per le nostre custom collection

Introduzione
Ne avevo parlato un po' di tempo fa qua sul mio blog. Se nel nostro domain model abbiamo creato una custom collection e poi vogliamo bindarla su una DataGridView, tale collection deve implementare l'interfaccia ITypedList. Questa interfaccia è di per sè abbastanza semplice: richiede l'implementazione di due soli metodi pubblici (GetItemProperties e GetListName). In pratica, il primo metodo ritorna un oggetto PropertyDescriptorCollection che rappresenta l'elenco delle proprietà che vogliamo bindare come colonne sulla DataGridView. Il secondo metodo ritorna una banale stringa con il nome della lista.

Facciamo un esempio pratico. Il class designer vale in questo caso molto più di mille parole:

Come è facilmente intuibile, la classe HockeyPlayer rappresenta un giocatore di hockey (nome, numero di maglia, peso, altezza ed elenco di falli subiti durante una partita). La classe Fault è il singolo fallo (tipo di fallo e quando è avvenuto). Poi esiste la classe FaultsCollection che non fa altro che ereditare direttamente da BindingList<Fault>. Se vogliamo bindare questa collection ad una DataGridView, dobbiamo utilizzare l'interfaccia ITypedList per intercettare il binding e specificare quali proprietà vogliamo ed in quale ordine. In questo caso è piuttosto semplice, perchè le proprietà sono solamente due, ma il problema c'è comunque e volevo risolverlo in un modo più elegante. Mi sono posto innanzitutto le seguenti domande:

  1. Non è assolutamente corretto che io come sviluppatore debba decidere durante lo sviluppo quali siano le colonne da far vedere, ed in quale ordine. L'utente potrebbe voler personalizzare la vista, potrebbe riordinare le colonne
  2. Non è assolutamente corretto che un business object debba sapere come mostrarsi. Mi piacerebbe quindi che ad ogni binding di FaultsCollection, tale classe richieda una sorta di Default View ad un'altra classe gemella, che invece implementa tutta la logica necessaria
  3. Mi piacerebbe che le informazioni sul binding vengano persistite in qualche modo, ad esempio su file. In questo modo, io decido in fase di sviluppo la vista standard, ma se poi l'utente me la cambia (re-ordering delle colonne sulla DataGridView) io devo accorgermene, salvare il tutto e riprendere successivamente

Tutte queste domande mi hanno portato a creare una piccola soluzione che voglio proporre sul mio blog.

Come ho risolto il mio piccolo problema
Innanzitutto, l'abbiamo detto prima. La classe FaultsCollection deve implementare ITypedList.

using System;
using System.ComponentModel;

namespace DataBindingSample
{
    
public class FaultsCollection : BindingList<Fault>, ITypedList
    {
        
#region ITypedList
        public 
PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
        {
            
// ritorno un oggetto PropertyDescriptorCollection
        
}
        
public string GetListName(PropertyDescriptor[] listAccessors)
        {
            
// ritorno "FaultsCollection"
        
}
        
#endregion
    
}
}

Quando viene chiamato uno dei due metodi previsti dall'interfaccia, non faccio altro che delegare un'altra classe allo scopo. Questa altra classe si chiama FaultsCollectionDefaultView e dispone di due metodi statici che non fanno altro che mappare GetItemProperties e GetListName. Il codice è riportato qui sotto.

public static class FaultCollectionDefaultView
{
    
public static PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        Type tp = 
typeof(Fault);
        PropertyDescriptorCollection m_OriginalList = TypeDescriptor.GetProperties(tp);

        PropertyDescriptorCollection m_SortedList = m_OriginalList.Sort(
new string[] { "Motivo" });
        m_SortedList.RemoveAt(2);

        
return (m_SortedList);
    }
    
public static string GetListName(PropertyDescriptor[] listAccessors)
    {
        
return "FaultsCollection";
    }
}

Il metodo GetItemProperties ottiene innanzitutto l'elenco delle property esposte dal singolo oggetto Fault: tale elenco viene gestito da m_OriginalList. Poi viene creato l'elenco vero e proprio che verrà utilizzato per il binding, usando solo la proprietà Motivo e rimuovendo la proprietà ID che non voglio mostrare mai all'utente finale.

In questo modo, non sarà direttamente la classe FaultsCollection a contenere queste codice, ma una classe gemella che invece contiene tutta la logica che serve per descrivere come una certa custom collection deve mostrarsi su una DataGridView.

Prossimo passo? Persistere su un file!
Il passo successivo dovrebbe migliorare in prestazioni ed in user-experience. L'idea è quella di andare a leggere su un file XML l'elenco delle properties da bindare, un elenco che potrebbe quindi anche esprimere direttamente l'ordine esatto di default. Invece di usare il metodo statico GetProperties di TypeDescriptor per ottenere un elenco preliminare dal quale poi togliere quello che non mi serve e riordinare, potrei direttamente andare a leggere su file le informazioni di binding.

In questo modo, inoltre, se l'utente finale riordina le colonne sulla DataGridView, non farei altro che persistere le nuove informazioni, per mantenerle tra una sessione di lavoro e l'altra. Non è solo una soluzione tecnica, ma anche una soluzione di design: non mi sembrava corretto che un oggetto venisse farcito di troppe responsabilità, delegando invece ad altri oggetti i relativi compiti.

powered by IMHO 1.3

Print | posted on venerdì 2 giugno 2006 23:32 | Filed Under [ Tecnologia ]

Feedback

Gravatar

# re: Una 'default view' per le nostre custom collection

Personalmente vedo ottimale l'implementazione dell'MVC: la classe di business, quindi, NON dovrebbe essere MAI bindata direttamente all'oggetto di UI (DataGridView) ma ad un oggetto "di mezzo" che gestirebbe le proprieta' da mostrare di volta in volta.
...sempre IMHO
Igor A.
03/06/2006 00:59 | Igor A.
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET