2013-08-26 13 views
11

Ho un Datagrid che deve essere riempito dinamicamente.Compilare un Datagrid con colonne dinamiche

Il TableLayout è come:

id | image | name | Description | Name-1 | Name-N 

Le prime 4 colonne sono statici gli altri sono dinamici. L'utente dovrebbe essere in grado di aggiungere tutti gli utenti che desidera.

Provo a confrontare i dati di più utenti mettendoli uno accanto all'altro nella tabella.

In questo momento ho una Listbox che contiene i nomi delle colonne generate dinamicamente e un metodo che riempie le colonne statiche. Posso anche caricare i dati per ogni utente. ora ho bisogno di unirli a un grande tavolo.

Il problema principale è ora: come inserire "Userdata" e il contenuto statico in un datagrid.

+0

è l'unico modo di visualizzare queste informazioni? –

+0

Non sono sicuro di cosa stai chiedendo. – Wr4thon

+0

Johannes vede la mia risposta, in modo che tu possa capire perché lo stavo chiedendo. –

risposta

20

Ci sono almeno tre modi per farlo:

  1. Modifica colonne del DataGrid manualmente dal code-behind
  2. Utilizzare un DataTable come ItemsSource *
  3. Utilizzare un CustomTypeDescriptor

    * consigliato per semplicità


Primo approccio: utilizzare code-behind per generare le colonne del DataGrid in fase di esecuzione. È semplice da implementare, ma forse ti sembra un po 'schifoso, specialmente se stai utilizzando MVVM. Così si sarebbe avere il DataGrid con colonne fisse:

<DataGrid x:Name="grid"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Binding="{Binding id}" Header="id" /> 
     <DataGridTextColumn Binding="{Binding image}" Header="image" /> 
    </DataGrid.Columns> 
</DataGrid> 

Quando hai il tuo "Nomi" pronto, quindi modificare la griglia con l'aggiunta/rimozione di colonne, ad esempio:

// add new columns to the data grid 
void AddColumns(string[] newColumnNames) 
{ 
    foreach (string name in newColumnNames) 
    { 
     grid.Columns.Add(new DataGridTextColumn { 
      // bind to a dictionary property 
      Binding = new Binding("Custom[" + name + "]"), 
      Header = name 
     }); 
    } 
} 

vorrete per creare una classe wrapper, che dovrebbe contenere la classe originale, oltre a un dizionario per contenere le proprietà personalizzate. Diciamo che la vostra classe di fila principale è "utente", allora che ci si vuole una classe wrapper qualcosa di simile:

public class CustomUser : User 
{ 
    public Dictionary<string, object> Custom { get; set; } 

    public CustomUser() : base() 
    { 
     Custom = new Dictionary<string, object>(); 
    } 
} 

popolano il ItemsSource con una collezione di questa nuova classe "CustomUser":

void PopulateRows(User[] users, Dictionary<string, object>[] customProps) 
{ 
    var customUsers = users.Select((user, index) => new CustomUser { 
     Custom = customProps[index]; 
    }); 
    grid.ItemsSource = customUsers; 
} 

Quindi legare insieme, per esempio:

var newColumnNames = new string[] { "Name1", "Name2" }; 
var users = new User[] { new User { id="First User" } }; 
var newProps = new Dictionary<string, object>[] { 
    new Dictionary<string, object> { 
     "Name1", "First Name of First User", 
     "Name2", "Second Name of First User", 
    }, 
}; 
AddColumns(newColumnNames); 
PopulateRows(users, newProps); 

2 ° approccio: usa uno DataTable. Questo fa uso dell'infrastruttura di tipo personalizzato sotto il cofano, ma è più facile da usare.Basta legare del ItemsSource a una proprietà DataTable.DefaultView DataGrid:

<DataGrid ItemsSource="{Binding Data.DefaultView}" AutoGenerateColumns="True" /> 

Quindi è possibile definire le colonne come più vi piace, ad esempio:

Data = new DataTable(); 

// create "fixed" columns 
Data.Columns.Add("id"); 
Data.Columns.Add("image"); 

// create custom columns 
Data.Columns.Add("Name1"); 
Data.Columns.Add("Name2"); 

// add one row as an object array 
Data.Rows.Add(new object[] { 123, "image.png", "Foo", "Bar" }); 

terzo approccio: Sfruttate l'estensibilità del Sistema di tipo .Net. In particolare, utilizzare un CustomTypeDescriptor. Questo ti permette di creare un tipo personalizzato in fase di runtime; che a sua volta ti permette di dire al DataGrid che il tuo tipo ha le proprietà "Nome1", "Nome2", ... "NomeN", o qualsiasi altra cosa tu voglia. Vedere here per un semplice esempio di questo approccio.

+2

Ho trovato che l'approccio DataTable è la soluzione più semplice ed efficiente. –

+0

Qualcuno ha generato automaticamente colonne in DataGrid con il metodo 3? Ho già definito un descrittore di tipo personalizzato, posso legare bene le sue proprietà, ma le colonne che generano automaticamente non funzionano. – Jesse

+0

cosa succede se vogliamo modificare e aggiornare i valori nella stessa griglia di dati – Shelly

0

Se non viene richiesto di dimostrare che in un unico grande DataGrid (tabella) allora si potrebbe avere un DataGrid con id, immagine, nome, descrizione e quando uno dei record è selezionata in quel DataGrid allora mostrare/aggiornare un ListBox con il nome di immagini correlate al record selezionato

+0

Beh, non penso che questo risolverà il mio problema. Ho una grande tabella che contiene alcuni dati (non importa quale) ora ho bisogno di confrontare più nomi con i record. Quindi per ogni record ho bisogno di "N" più Colummn per confrontare direttamente due o più persone. e. g. : Record 1: 1; tmp.png; Foo; bar; riuscito; non riuscito Record 2: 2; tmp2.png; Foo1; bar2; non riuscito; riuscito – Wr4thon

4

2o approccio: utilizzare un DataTable. Questo fa uso dell'infrastruttura di tipo personalizzato sotto il cofano, ma è più facile da usare. È sufficiente associare l'oggetto ItemsGrid di DataGrid a una proprietà DataTable.DefaultView:

Questo ha funzionato quasi ma invece di legarsi alla proprietà proprietà DataTable.DefaultView ho creato una proprietà di tipo DataView e associata a tale.

<DataGrid ItemsSource="{Binding DataView, Mode=TwoWay}" AutoGenerateColumns="True" />

Questo permette l'associazione di essere bidirezionale, legandosi al DataTable.DefaultView non può essere un TwoWay vincolante. Nella vista del modello

public DataView DataView 
    { 
     get { return _dataView; } 
     set 
     { 
      _dataView = value; 
      OnPropertyChanged("DataView"); 
     } 
    } 

Con questa configurazione non ho potuto solo definire le colonne dinamicamente quando la vista del modello viene inizializzato, ma potrebbe aggiornare e modificare la tabella di dati in modo dinamico in qualsiasi momento. Utilizzando l'approccio definito da McGarnagle in precedenza, lo schema di visualizzazione non si aggiornava quando DataTable veniva aggiornato con una nuova origine dati.

Problemi correlati