програмно додавати стовпці та рядки до WPF Datagrid


75

Я новачок у WPF. Я просто хочу знати, як ми повинні програмно додавати стовпці та рядки до DataGrid у WPF. Те, як ми звикли це робити у вікнах. створити стовпці та рядки таблиці та прив’язати їх до DataGrid.

Я вважаю, що WPF DataGrid трохи відрізняється від того, що використовується у форматі ASP.net та Windows (виправте мене, якщо я помиляюся).

У мене є кількість рядків і стовпців, які мені потрібно намалювати в DataGrid, щоб користувач міг редагувати дані в комірках.

Відповіді:


74

Щоб програмно додати рядок:

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

Щоб програмно додати стовпець:

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

Перегляньте цю публікацію на дошці обговорень WPF DataGrid для отримання додаткової інформації.


7
-1: оскільки ви показуєте болісно легку частину, але не те, як насправді прив’язати дані до цих стовпців, доданих під час виконання. Я впевнений, що Енді хоче створити програму, яка відображає певні дані, а не лише імена стовпців.
JohnB

Це просто питання встановлення властивостей у DataGridTextColumn. Я оновив відповідь.
Джон Мичек

+1: Я підтвердив, що це працює, дякую. Я також виявив, що коли ви додаєте квадратні дужки, тобто Binding("[FirstName]") див. Мою попередню відповідь нижче , це працює, але це значно повільніше при прив’язуванні великих наборів даних.
JohnB

1
Як DataItemі об’єкт, як він повинен виглядати?
C4d

Чи є спосіб додати заголовок із декількома стовпцями за допомогою цього коду?
Денис

30

спробуйте це, це працює на 100%: додайте стовпці та рядки програмно: спочатку потрібно створити клас елемента:

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

        }

Чи є спосіб додати заголовок із декількома стовпцями за допомогою цього коду?
Денис

24

У мене була та сама проблема. Додавання нових рядків до WPF DataGridвимагає хитрості. DataGridпокладається на поля властивостей об'єкта елемента. ExpandoObjectдозволяє динамічно додавати нові властивості. У наведеному нижче коді пояснюється, як це зробити:

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

// редагувати:

Зауважте, що не таким чином слід використовувати компонент, однак це значно спрощує, якщо у вас є лише програмно сформовані дані (наприклад, у моєму випадку: послідовність функцій та вихід нейронної мережі).


@ bartek-dzieńkowski Awesome
Mahdi Khalili

12

Я знайшов рішення, яке додає стовпці під час виконання та прив'язує до DataTable.

На жаль, маючи 47 стовпців, визначених таким чином, він не прив’язується до даних досить швидко для мене. Будь-які пропозиції?

xaml

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

xaml.cs за допомогою 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;
}

Ви знайшли якесь рішення для цього тоді ??
321X,

2
Чому ви використовуєте "[{0}]" у шляху прив'язки? Це не працює для мене, але коли я просто використовую назву без квадрата та кучерів, це працює?
smerlung

4

edit : вибачте, у мене вже немає коду, згаданого нижче. Це було акуратне рішення, хоч і складне.


Я опублікував зразок проекту, що описує, як використовувати PropertyDescriptor та лямбда-делегати з динамічними ObservableCollection та DynamicObject для заповнення сітки з сильно набраними визначеннями стовпців.

Стовпці можна додавати / видаляти під час виконання динамічно . Якщо ваші дані не є об'єктом з відомим типом, ви можете створити структуру даних, яка дозволить доступ за будь-якою кількістю стовпців і вказати PropertyDescriptor для кожного "стовпця".

Наприклад:

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

Ви можете визначити стовпці таким чином:

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) 

Або ще краще, у випадку якихось реальних об’єктів

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

Ви можете вказати стовпці, що сильно набираються (пов'язані з вашою моделлю даних):

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

Потім ви просто прив'язуєтесь до колекцій користувачів і стовпці автоматично генеруються, коли ви їх визначаєте. Рядки, передані дескрипторам властивостей, є іменами заголовків стовпців. Під час виконання ви можете додати більше PropertyDescriptors до 'Користувачі', додати ще один стовпець до сітки.


@doblak Я вважаю, що це саме те, що мені потрібно. Ви все ще маєте код свого рішення?
zhangz

@zhangz оновив відповідь, див. цю публікацію щодо ідеї DynamicPropertyDescriptor
doblak

3

Якщо у вас вже є прив'язка даних, John Myczek відповідь завершена.
Якщо ні, у вас є принаймні 2 варіанти, які я знаю, якщо ви хочете вказати джерело своїх даних. (Однак я не впевнений, чи відповідає це чи ні більшості вказівок, таких як MVVM)

варіант 1: як сказав ДжонБ. Але я думаю, що вам слід використовувати власну визначену колекцію замість слабо набраної таблиці даних (не ображайте, але ви не можете зрозуміти з коду, що представляє кожен стовпець)

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}>

у xaml.cs

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

Якщо для вашого типу визначено властивість FirstName , ви можете зробити те, на що вказав Джон Myczek.

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

Це, очевидно, не працює, якщо ви не знаєте властивостей, які вам потрібно буде показати у вашій dataGrid, але якщо це так, у вас буде більше проблем, і я вважаю, що тут це поза сферою застосування.


0

Для прив'язки DataTable в DataGridTextColumn в 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;

-1

Якщо у вас вже є прив'язка даних, John Myczek відповідь завершена. Якщо ні, у вас є принаймні 2 варіанти, які я знаю, якщо ви хочете вказати джерело своїх даних. (Однак я не впевнений, чи відповідає це чи ні більшості вказівок, таких як MVVM)

Потім ви просто прив'язуєтесь до колекцій користувачів і стовпці автоматично генеруються, коли ви їх визначаєте. Рядки, передані дескрипторам властивостей, є іменами заголовків стовпців. Під час виконання ви можете додати більше PropertyDescriptors до 'Користувачі', додати ще один стовпець до сітки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.