Fügen Sie dem WPF-Datagrid programmgesteuert Spalten und Zeilen hinzu

75

Ich bin neu bei WPF. Ich möchte nur wissen, wie wir einem DataGrid in WPF programmgesteuert Spalten und Zeilen hinzufügen sollen. So wie wir es früher in Windows-Formularen gemacht haben. Erstellen Sie Tabellenspalten und -zeilen und binden Sie sie an DataGrid.

Ich glaube, WPF DataGrid ist etwas anders als das, das in ASP.net und Windows Form verwendet wird (korrigieren Sie mich, wenn ich falsch liege).

Ich habe die Anzahl der Zeilen und Spalten, die ich in DataGrid zeichnen muss, damit der Benutzer die Daten in den Zellen bearbeiten kann.

Andy
quelle

Antworten:

74

So programmgesteuert eine Zeile hinzufügen:

DataGrid.Items.Add(new DataItem());

So programmgesteuert eine Spalte hinzufügen:

DataGridTextColumn textColumn = new DataGridTextColumn(); 
textColumn.Header = "First Name"; 
textColumn.Binding = new Binding("FirstName"); 
dataGrid.Columns.Add(textColumn); 

Weitere Informationen finden Sie in diesem Beitrag im WPF DataGrid-Diskussionsforum.

John Myczek
quelle
7
-1: weil Sie den schmerzhaft einfachen Teil zeigen, aber nicht, wie Daten tatsächlich an diese zur Laufzeit hinzugefügten Spalten gebunden werden. Ich bin sicher, dass Andy eine Anwendung erstellen möchte, die Daten anzeigt, nicht nur Spaltennamen.
JohnB
Es geht nur darum, Eigenschaften für die DataGridTextColumn festzulegen. Ich habe die Antwort aktualisiert.
John Myczek
+1: Ich habe bestätigt, dass das funktioniert, danke. Ich habe auch festgestellt, dass das Hinzufügen der eckigen Klammern, dh Binding("[FirstName]") meine vorherige Antwort unten , funktioniert, beim Binden großer Datenmengen jedoch erheblich langsamer ist.
JohnB
1
Wie muss DataItemein Objekt aussehen?
C4d
Gibt es eine Möglichkeit, mit diesem Code mehrspaltige Header hinzuzufügen?
Denis
29

Versuchen Sie dies, es funktioniert zu 100%: Fügen Sie Spalten und Zeilen programmgesteuert hinzu: Sie müssen zuerst eine Elementklasse erstellen:

public class Item
        {
            public int Num { get; set; }
            public string Start { get; set; }
            public string Finich { get; set; }
        }

        private void generate_columns()
        {
            DataGridTextColumn c1 = new DataGridTextColumn();
            c1.Header = "Num";
            c1.Binding = new Binding("Num");
            c1.Width = 110;
            dataGrid1.Columns.Add(c1);
            DataGridTextColumn c2 = new DataGridTextColumn();
            c2.Header = "Start";
            c2.Width = 110;
            c2.Binding = new Binding("Start");
            dataGrid1.Columns.Add(c2);
            DataGridTextColumn c3 = new DataGridTextColumn();
            c3.Header = "Finich";
            c3.Width = 110;
            c3.Binding = new Binding("Finich");
            dataGrid1.Columns.Add(c3);

            dataGrid1.Items.Add(new Item() { Num = 1, Start = "2012, 8, 15", Finich = "2012, 9, 15" });
            dataGrid1.Items.Add(new Item() { Num = 2, Start = "2012, 12, 15", Finich = "2013, 2, 1" });
            dataGrid1.Items.Add(new Item() { Num = 3, Start = "2012, 8, 1", Finich = "2012, 11, 15" });

        }
aminescm
quelle
Gibt es eine Möglichkeit, mit diesem Code mehrspaltige Header hinzuzufügen?
Denis
23

Ich hatte das gleiche Problem. Das Hinzufügen neuer Zeilen zu WPF DataGriderfordert einen Trick. DataGridstützt sich auf Eigenschaftsfelder eines Objektobjekts. ExpandoObjectermöglicht das dynamische Hinzufügen neuer Eigenschaften. Der folgende Code erklärt, wie es geht:

// using System.Dynamic;

DataGrid dataGrid;

string[] labels = new string[] { "Column 0", "Column 1", "Column 2" };

foreach (string label in labels)
{
    DataGridTextColumn column = new DataGridTextColumn();
    column.Header = label;
    column.Binding = new Binding(label.Replace(' ', '_'));

    dataGrid.Columns.Add(column);
}

int[] values = new int[] { 0, 1, 2 };

dynamic row = new ExpandoObject();

for (int i = 0; i < labels.Length; i++)
    ((IDictionary<String, Object>)row)[labels[i].Replace(' ', '_')] = values[i];

dataGrid.Items.Add(row);

//bearbeiten:

Beachten Sie, dass dies nicht die Art und Weise ist, wie die Komponente verwendet werden soll. Dies vereinfacht jedoch erheblich, wenn Sie nur programmgesteuert Daten generiert haben (z. B. in meinem Fall: eine Folge von Funktionen und die Ausgabe eines neuronalen Netzwerks).

Bartek Dzieńkowski
quelle
@ Bartek-Dzieńkowski Awesome
Mahdi Khalili
11

Ich habe eine Lösung gefunden, die zur Laufzeit Spalten hinzufügt und an a bindet DataTable.

Leider sind 47 Spalten, die auf diese Weise definiert wurden, für mich nicht schnell genug an die Daten gebunden. Irgendwelche Vorschläge?

xaml

<DataGrid
  Name="dataGrid"
  AutoGenerateColumns="False"
  ItemsSource="{Binding}">
</DataGrid>

xaml.cs using System.Windows.Data;

if (table != null) // table is a DataTable
{
  foreach (DataColumn col in table.Columns)
  {
    dataGrid.Columns.Add(
      new DataGridTextColumn
      {
        Header = col.ColumnName,
        Binding = new Binding(string.Format("[{0}]", col.ColumnName))
      });
  }

  dataGrid.DataContext = table;
}
JohnB
quelle
Haben Sie damals eine Lösung dafür gefunden?
321X
2
Warum verwenden Sie "[{0}]" im Bindungspfad? Es funktioniert nicht für mich, aber wenn ich nur den Namen ohne Quadrat und Locken verwende, dann funktioniert es?
smerlung
4

edit : sorry, ich habe den unten genannten code nicht mehr. Es war eine saubere Lösung, obwohl komplex.


Ich habe ein Beispielprojekt veröffentlicht, in dem beschrieben wird, wie PropertyDescriptor- und Lambda-Delegaten mit dynamischer ObservableCollection und DynamicObject verwendet werden, um ein Raster mit stark typisierten Spaltendefinitionen zu füllen .

Spalten können zur Laufzeit dynamisch hinzugefügt / entfernt werden . Wenn Ihre Daten kein Objekt mit bekanntem Typ sind, können Sie eine Datenstruktur erstellen, die den Zugriff für eine beliebige Anzahl von Spalten ermöglicht, und für jede "Spalte" einen PropertyDescriptor angeben.

Zum Beispiel:

IList<string> ColumnNames { get; set; }
//dict.key is column name, dict.value is value
Dictionary<string, string> Rows { get; set; }

Sie können Spalten folgendermaßen definieren:

var descriptors= new List<PropertyDescriptor>();
//retrieve column name from preprepared list or retrieve from one of the items in dictionary
foreach(var columnName in ColumnNames)
    descriptors.Add(new DynamicPropertyDescriptor<Dictionary, string>(ColumnName, x => x[columnName]))
MyItemsCollection = new DynamicDataGridSource(Rows, descriptors) 

Oder noch besser bei einigen realen Objekten

public class User 
{
    public string FirstName { get; set; }
    public string LastName{ get; set; }
    ...
}

Sie können stark typisierte Spalten angeben (bezogen auf Ihr Datenmodell):

var propertyDescriptors = new List<PropertyDescriptor>
{
    new DynamicPropertyDescriptor<User, string>("First name", x => x.FirstName ),
    new DynamicPropertyDescriptor<User, string>("Last name", x => x.LastName ),
    ...
}

var users = retrieve some users

Users = new DynamicDataGridSource<User>(users, propertyDescriptors, PropertyChangedListeningMode.Handler);

Dann binden Sie einfach an Benutzer Sammlungen und Spalten werden automatisch generiert, wenn Sie sie spezifizieren. An Eigenschaftsbeschreibungen übergebene Zeichenfolgen sind Namen für Spaltenüberschriften. Zur Laufzeit können Sie den 'Benutzern' weitere PropertyDescriptors hinzufügen und dem Raster eine weitere Spalte hinzufügen.

Doblak
quelle
@doblak Ich finde, das ist genau das, was ich brauche. Haben Sie noch den Code Ihrer Lösung?
Zhangz
@zhangz aktualisiert die Antwort, siehe diesen Beitrag für DynamicPropertyDescriptor Idee: jopinblog.wordpress.com/2007/05/12/…
Doblak
3

Wenn Sie die Datenbindung bereits eingerichtet haben, ist die Antwort von John Myczek vollständig.
Wenn nicht, haben Sie mindestens zwei mir bekannte Optionen, wenn Sie die Quelle Ihrer Daten angeben möchten. (Ich bin mir jedoch nicht sicher, ob dies den meisten Richtlinien wie MVVM entspricht oder nicht.)

Option 1: wie JohnB sagte. Aber ich denke, Sie sollten Ihre eigene definierte Sammlung anstelle einer schwach typisierten DataTable verwenden (keine Beleidigung, aber Sie können anhand des Codes nicht erkennen, was jede Spalte darstellt).

xaml.cs

DataContext = myCollection;

//myCollection is a `ICollection<YourType>` preferably
`ObservableCollection<YourType>

 - option 2) Declare the name of the Datagrid in xaml

        <WpfToolkit:DataGrid Name=dataGrid}>

in xaml.cs

CollectionView myCollectionView = 
      (CollectionView)CollectionViewSource.GetDefaultView(yourCollection);
dataGrid.ItemsSource = myCollectionView;

Wenn für Ihren Typ eine Eigenschaft FirstName definiert ist, können Sie das tun, worauf John Myczek hingewiesen hat.

DataGridTextColumn textColumn = new DataGridTextColumn(); 
dataColumn.Header = "First Name"; 
dataColumn.Binding = new Binding("FirstName"); 
dataGrid.Columns.Add(textColumn); 

Dies funktioniert offensichtlich nicht, wenn Sie keine Eigenschaften kennen, die Sie in Ihrem dataGrid anzeigen müssen, aber wenn dies der Fall ist, werden Sie mehr Probleme haben, und ich glaube, dass dies hier nicht möglich ist.

HCP
quelle
0

So binden Sie die DataTable in die DataGridTextColumn in CodeBehind xaml

<DataGrid
  Name="TrkDataGrid"
  AutoGenerateColumns="False"
  ItemsSource="{Binding}">
</DataGrid>

xaml.cs

  foreach (DataColumn col in dt.Columns)
  {
    TrkDataGrid.Columns.Add(
      new DataGridTextColumn
      {
        Header = col.ColumnName,
        Binding = new Binding(string.Format("[{0}]", col.ColumnName))
      });
  }

  TrkDataGrid.ItemsSource= dt.DefaultView;
Maghalakshmi Saravana
quelle
-1

Wenn Sie die Datenbindung bereits eingerichtet haben, ist die Antwort von John Myczek vollständig. Wenn nicht, haben Sie mindestens zwei mir bekannte Optionen, wenn Sie die Quelle Ihrer Daten angeben möchten. (Ich bin mir jedoch nicht sicher, ob dies den meisten Richtlinien wie MVVM entspricht oder nicht.)

Dann binden Sie einfach an Benutzer Sammlungen und Spalten werden automatisch generiert, wenn Sie sie spezifizieren. An Eigenschaftsbeschreibungen übergebene Zeichenfolgen sind Namen für Spaltenüberschriften. Zur Laufzeit können Sie den 'Benutzern' weitere PropertyDescriptors hinzufügen und dem Raster eine weitere Spalte hinzufügen.

Senar
quelle