2013-08-26 15 views
11

Mam Datagrid, który musi zostać wypełniony dynamicznie.Wypełnianie Datagrida dynamicznymi Kolumnami

TableLayout jest jak:

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

Pierwsze 4 kolumny są statyczne inni są dynamiczne. Użytkownik powinien mieć możliwość dodania tylu użytkowników, ile chce.

Próbuję porównać dane wielu użytkowników, umieszczając je obok siebie w tabeli.

Teraz mam Listbox, który zawiera Nazwy dynamicznie generowanych Kolumn i metodę, która wypełnia statyczne kolumny. Mogę też załadować dane dla każdego użytkownika. teraz muszę połączyć je z jednym dużym stołem.

Głównym problemem jest teraz: Jak umieścić "Userdata" i statyczną zawartość w jednym datagrid.

+0

jest to jedyny sposób wyświetlania tych informacji? –

+0

Nie jestem pewien, o co pytasz. – Wr4thon

+0

Johannes zobaczył moją odpowiedź, abyś mógł zobaczyć, dlaczego o to pytam. –

Odpowiedz

20

Istnieją co najmniej trzy sposoby osiągnięcia tego celu:

  1. Modyfikuj kolumny DataGrid jest ręcznie z kodu źródłowego
  2. użytkowania DataTable jako ItemsSource *
  3. Użyj CustomTypeDescriptor

    * zalecane dla prostoty:


Pierwsze podejście: użyj kodu z tyłu, aby wygenerować kolumny DataGrid w czasie wykonywania. Jest to łatwe do wdrożenia, ale może wydawać się nieco hackish, szczególnie jeśli używasz MVVM. Tak, że masz DataGrid ze stałymi kolumnach:

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

Kiedy masz swoje „Names” gotowy, a następnie zmodyfikować siatkę przez dodawanie/usuwanie kolumn, np:

// 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 
     }); 
    } 
} 

Będziemy chcieli Aby utworzyć klasę opakowania, która powinna zawierać klasę oryginalną oraz słownik zawierający niestandardowe właściwości. Załóżmy, że główny klasa wiersz jest „User”, po czym tylko chcesz klasy otoki coś takiego:

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

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

zapełnić ItemsSource z kolekcją tej nowej klasy „CustomUser”:

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

Więc wiążąc je ze sobą, na przykład:

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-ty podejście: użyj DataTable. Wykorzystuje to niestandardową infrastrukturę pod maską, ale jest łatwiejsza w użyciu.Wystarczy powiązać DataGrid na ItemsSource do DataTable.DefaultView nieruchomości:

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

Następnie można zdefiniować kolumny jednak chcesz, np:

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" }); 

3-ty podejście: skorzystać z rozciągliwości System typu .Net. W szczególności używaj CustomTypeDescriptor. Umożliwia to tworzenie niestandardowego typu w czasie wykonywania; co z kolei pozwala powiedzieć DataGrid, że twój typ ma właściwości "Nazwa1", "Nazwa2", ... "NazwaN" lub cokolwiek innego chcesz. Zobacz here dla prostego przykładu tego podejścia.

+2

Uważam, że podejście DataTable jest najłatwiejszym i najbardziej wydajnym rozwiązaniem. –

+0

Czy ktoś pomyślnie generował automatycznie kolumny w DataGrid przy użyciu metody 3? Mam już zdefiniowany niestandardowy deskryptor typu, mogę go powiązać z jego właściwościami, ale automatyczne generowanie kolumn nie działa. – Jesse

+0

co jeśli chcemy edytować i aktualizować wartości w tej samej siatce danych – Shelly

0

Jeżeli nie są wymagane, aby pokazać, że w jednym wielkim DataGrid (tabela), a następnie można mieć DataGrid z id, obrazu, nazwa, opis i gdy jeden z rekordów jest wybrany na tym DataGrid następnie wyświetlasz/odświeża ListBox z nazwami obrazów, które są powiązane z wybranym rekordem

+0

Cóż, nie sądzę, że to rozwiąże mój problem. Mam jedną dużą tabelę, która zawiera pewne dane (bez względu na whitch), teraz muszę porównać wiele nazw z rekordami. Więc dla każdego rekordu potrzebuję "N" więcej Colummnów, aby bezpośrednio porównać dwie lub więcej Osób. mi. sol. : Record 1: 1; tmp.png; Foo; bar; powiodło się; nie udało się Record 2: 2; tmp2.png; Foo1; bar2; nie powiodło się; udało się – Wr4thon

4

2. podejście: użyj DataTable. Wykorzystuje to niestandardową infrastrukturę pod maską, ale jest łatwiejsza w użyciu. Wystarczy powiązać obiekt ItemsSource DataGrid z właściwością DataTable.DefaultView:

To prawie działało, ale zamiast powiązania z właściwością właściwości DataTable.DefaultView utworzyłem właściwość typu DataView i powiązano z nią.

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

umożliwia to, że wiązanie będzie dwukierunkowe, wiązanie do DataTable.DefaultView nie może być TwoWay wiążące. W widoku modelu

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

Z tej konfiguracji nie mogę tylko określić kolumny dynamicznie kiedy Widok Model jest inicjowany, ale może aktualizować i zmieniać dynamicznie tabelę danych w dowolnym momencie. Używając podejścia zdefiniowanego przez McGarnagle powyżej, schemat widoku nie był odświeżany, gdy DataTable została zaktualizowana o nowe źródło danych.