Si desidera fare in modo che l'utente di un dato applicativo, una volta personalizzata una DataGrid riordinando colonne o modificandone le ampiezze, abbia la possibilità di salvare tali variazioni preferenziali, e che al riavvio del programma queste vengano caricate ed applicate alla griglia stessa. Presento qui a seguire una classe atta allo scopo, mostrandone inoltre un semplice scenario di utilizzo.

Il codice è largamente commentato per essere il più chiaro possibile. Le funzioni sono dichiarate Shared per praticità nell'utilizzo statico della classe. In essa si fa utilizzo delle classi DataSet e DataTable al fine di sfruttare i comodi metodi di accesso a file XML, tramite i quali verrà realizzata l'archiviazione dei parametri di colonna.


Imports System.Data
Public Class emDataGridOptions
    ' Si dichiara come costante un ipotetico percorso (modificabile) nel quale archiviare i files opzioni
    ' delle griglie utilizzate a programma
    Const _DATAGRID_OPTIONS_DIR As String = "C:\tmp\"
    ' Dichiarazione estensione di default applicata ai files di opzione
    Const _DATAGRID_OPTIONS_EXT As String = ".di"
    ' ===============================================================================
    ' Funzione Privata per la restituzione del percorso completo di salvataggio opzioni
    ' ===============================================================================
 
    Private Shared Function ComposeGridOptionsFile(gridName) As String
        ' Viene qui ritornato un path completo al file opzioni, composto dal percorso costante di archiviazione,
        ' il nome della griglia a cui si applicano le opzioni, l'estensione indicata del file
        Return _DATAGRID_OPTIONS_DIR & gridName & _DATAGRID_OPTIONS_EXT
    End Function
 
    ' ===============================================================================
    ' Sub Pubblica/Statica per il salvataggio delle opzioni DataGrid
    ' ===============================================================================
 
    Public Shared Sub SaveGridOptions(dg As DataGrid)
        ' Viene creato un DataSet di nome pari a quello di griglia, al cui interno è generato un DataTable
        ' di nome "columns".
 
        Dim columns As New DataSet(dg.Name)
        Dim coltable As New DataTable("columns")
 
        ' Si vogliono qui salvare solo alcune delle possibili impostazioni di visualizzazione colonna
        ' Sarà necessario creare nella DataTable tante colonne quanti sono i campi da salvare, prestando attenzione
        ' a specificare per ciascuno un tipo di dati congruente con quello della corrispondente proprietà
 
        With coltable
            .Columns.Add("DisplayIndex", Type.GetType("System.Int32"))
            .Columns.Add("Width", Type.GetType("System.Double"))
            .Columns.Add("Visibility", Type.GetType("System.Int32"))
            .Columns.Add("SortDirection", Type.GetType("System.Int32"))
        End With
 
        columns.Tables.Add(coltable)
 
        ' Viene quindi eseguito un ciclo sulle colonne della DataGrid indicata, aggiungendo alla DataTable
        ' un numero di righe uguale a quello delle colonne di griglia, ciascuna corredata dai valori di
        ' proprietà acquisiti dal controllo origine
 
        For Each c As DataGridColumn In dg.Columns
            coltable.Rows.Add(New Object() {c.DisplayIndex,
                                            c.Width.DisplayValue,
                                            c.Visibility,
                                            c.SortDirection})
        Next
 
        ' Infine, tramite il metodo WriteXml(), viene salvato un file XML contenente i parametri estratti dalle colonne
        columns.WriteXml(ComposeGridOptionsFile(dg.Name))
    End Sub
 
    ' ===============================================================================
 
    ' Sub Pubblica/Statica per il caricamento delle opzioni DataGrid
    ' ===============================================================================
 
    Public Shared Sub LoadGridOptions(dg As DataGrid)
        ' Se il file non esiste, non si deve proseguire oltre nel caricamento opzioni
 
        If Not (IO.File.Exists(ComposeGridOptionsFile(dg.Name))) Then Exit Sub
        ' Viene generato un nuovo DataSet, successivamente popolato da file tramite metodo ReadXml()
 
        Dim columns As New DataSet(dg.Name)
        columns.ReadXml(ComposeGridOptionsFile(dg.Name))
        ' Viene eseguito un ciclo sulle colonne di griglia: per ciascuna di esse, vengono lette
        ' ed applicate le proprietà dei vari campi sulla tabella zero del DataSet
 
        Dim ii As Integer = 0
 
        For Each c As DataGridColumn In dg.Columns
 
            c.DisplayIndex = columns.Tables(0).Rows(ii).Item("DisplayIndex")
            c.Width = Double.Parse(columns.Tables(0).Rows(ii).Item("Width"))
            c.Visibility = columns.Tables(0).Rows(ii).Item("Visibility")
 
            ' Il caso della SortDirection è particolare: se non è impostato un ordinamento, nel file XML non
            ' sarà presente la corrispondente entità: è quindi necessario valutare eventuali valori Nothing
 
            Dim sortDirection As Nullable(Of Integer) = Nothing
 
            If Not (columns.Tables(0).Rows(ii).Item("SortDirection").Equals(DBNull.Value)) Then sortDirection = Integer.Parse(columns.Tables(0).Rows(ii).Item("SortDirection"))
 
            ' Se è specificata una direzione di sort, è necessario eseguire l'ordinamento secondo la colonna specificata
            ' Viene quindi popolato l'elenco delle descrizioni di ordinamento tramite il valore letto e la proprietà
            ' SortMemberPath di colonna, ed eseguito quindi un refresh degli Items di griglia
 
            If Not (sortDirection Is Nothing) Then
                c.SortDirection = sortDirection
                dg.Items.SortDescriptions.Add(New ComponentModel.SortDescription(c.SortMemberPath, c.SortDirection))
                dg.Items.Refresh()
            End If
 
            ii += 1
        Next
    End Sub
End Class



Scenario di utilizzo
Lo scenario di utilizzo più tipico è certamente rappresentato dall'ingresso in una Window (nel caso del caricamento) e dall'uscita al termine del ciclo di vita dell'applicazione (nel caso del salvataggio).  Ipotizzando una Window di nome MainWindow, sulla quale implementare un controllo DataGrid di nome DataGrid1, potremo quindi sfruttare gli eventi Loaded() e Closing(), rispettivamente per le operazioni di caricamento opzioni e loro salvataggio. Nel contesto di detti eventi sarà quindi possibile richiamare le funzioni statiche, fornendo loro come parametro il controllo griglia sul quale eseguire le operazioni per l'archiviazione delle informazioni di colonna.

Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
   'Eseguire qui le operazioni preliminari, tra cui il binding dei dati sulla griglia
    emDataGridOptions.LoadGridOptions(DataGrid1)
End Sub
 
Private Sub MainWindow_Closing(sender As Object, e As ComponentModel.CancelEventArgs) Handles Me.Closing
    emDataGridOptions.SaveGridOptions(DataGrid1)
End Sub