Crea modello oggetto WPF DINAMICAMENTE in fase di esecuzione
Domanda
In fase di esecuzione voglio creare dinamicamente colonne di griglia (o un altro layout di visualizzazione) in un ListView WPF. Non conosco prima il numero e i nomi delle colonne.
Voglio essere in grado di fare:
MyListView.ItemSource = MyDataset;
MyListView.CreateColumns ();
Soluzione
Proverei il seguente approccio:
A) è necessario che la casella di riepilogo visualizzi la visualizzazione griglia - credo che tu l'abbia già fatto
B) definire uno stile per GridViewColumnHeader:
<Style TargetType="{x:Type GridViewColumnHeader}" x:Key="gridViewColumnStyle">
<EventSetter Event="Click" Handler="OnHeaderClicked"/>
<EventSetter Event="Loaded" Handler="OnHeaderLoaded"/>
</Style>
nel mio caso, avevo un sacco di altre proprietà impostate, ma nello scenario di base - avresti bisogno di Loaded event. Facendo clic: è utile se si desidera aggiungere funzionalità di ordinamento e filtro.
C) nel codice della visualizzazione elenco, associa il modello con la visualizzazione griglia:
public MyListView()
{
InitializeComponent();
GridView gridViewHeader = this.listView.View as GridView;
System.Diagnostics.Debug.Assert(gridViewHeader != null, "Expected ListView.View should be GridView");
if (null != gridViewHeader)
{
gridViewHeader.ColumnHeaderContainerStyle = (Style)this.FindResource("gridViewColumnStyle");
}
}
D) quindi nel tuo gestore OnHeaderLoaded, puoi impostare un modello corretto basato sui dati della colonna
void OnHeaderLoaded(object sender, RoutedEventArgs e)
{
GridViewColumnHeader header = (GridViewColumnHeader)sender;
GridViewColumn column = header.Column;
// seleziona e applica qui il tuo modello di dati.
e.Handled = true;
}
E) Immagino che dovresti anche acquisire la proprietà della proprietà di dipendenza ItemsSource e gestirne l'evento modificato.
ListView.ItemsSourceProperty.AddOwner(typeof(MyListView), new PropertyMetadata(OnItemsSourceChanged));
static void OnItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MyListView view = (MyListView)sender;
//do reflection to get column names and types
//and for each column, add it to your grid view:
GridViewColumn column = new GridViewColumn();
//set column properties here...
view.Columns.Add(column);
}
la stessa classe GridViewColumn non ha molte proprietà, quindi potresti voler aggiungere alcune informazioni lì usando le proprietà associate - cioè come un tag di colonna univoco - molto probabilmente l'intestazione verrà utilizzata per la localizzazione e non dovrai inoltrarla su questa .
In generale, questo approccio, anche se piuttosto complicato, ti permetterà di estendere facilmente la tua funzionalità di visualizzazione elenco.
Altri suggerimenti
È possibile aggiungere colonne in modo dinamico a un ListView utilizzando Proprietà collegate. Dai un'occhiata a questo articolo sul CodeProject , spiega esattamente che ...
Da MSDN:
MyListBox.ItemsSource = view;
ListView myListView = new ListView();
GridView myGridView = new GridView();
myGridView.AllowsColumnReorder = true;
myGridView.ColumnHeaderToolTip = "Employee Information";
GridViewColumn gvc1 = new GridViewColumn();
gvc1.DisplayMemberBinding = new Binding("FirstName");
gvc1.Header = "FirstName";
gvc1.Width = 100;
myGridView.Columns.Add(gvc1);
GridViewColumn gvc2 = new GridViewColumn();
gvc2.DisplayMemberBinding = new Binding("LastName");
gvc2.Header = "Last Name";
gvc2.Width = 100;
myGridView.Columns.Add(gvc2);
GridViewColumn gvc3 = new GridViewColumn();
gvc3.DisplayMemberBinding = new Binding("EmployeeNumber");
gvc3.Header = "Employee No.";
gvc3.Width = 100;
myGridView.Columns.Add(gvc3);
//ItemsSource is ObservableCollection of EmployeeInfo objects
myListView.ItemsSource = new myEmployees();
myListView.View = myGridView;
myStackPanel.Children.Add(myListView);
Avere un DataTemplateselector per selezionare uno dei modelli predefiniti (dello stesso tipo di dati) e applicare il selettore a ListView. Puoi avere altrettanti DataTemplates con colonne diverse.
Puoi utilizzare un DataTemplateSelector per restituire un DataTemplate che hai creato dinamicamente nel codice. Tuttavia, questo è un po 'noioso e più complicato rispetto all'utilizzo di uno predefinito da XAML, ma è ancora possibile. Dai un'occhiata a questo esempio: http: //dedjo.blogspot .com / 2007/03 / creazione-DataTemplates-da-code.html
Per esperienza, posso consigliarti di evitare modelli di dati dinamici se puoi aiutarlo ... piuttosto usa i consigli qui forniti per creare esplicitamente le colonne ListView, piuttosto che provare a creare un DataTemplate dinamicamente.
Il motivo è che FrameworkElementFactory (o qualunque sia il nome della classe per la produzione di DataTemplates in fase di esecuzione) è un po 'confuso da usare (ed è deprecato a favore dell'uso di XAML per i modelli dinamici) - in entrambi i casi si ottiene un impatto sulle prestazioni.