Как сделать автоматическую генерацию строк и колонок, чтобы получилась таблица

Подскажите пожалуйста.

С помощью каких сигнатур классов и xaml контрола можно реализовать такую таблицу, чтобы:

  1. Кол-во строк генерировалось автоматически в зависимости от кол-ва значений из источника, например коллекция студентов.
  2. и автоматически генерировались колонки с названием предметов в зависимости от значений из источника, например коллекция предметов.
  3. каждая пустая ячейка может принимать данные, чтобы можно было сохранить и показать снова.
  4. Какие правильные сигнатуры классов использовать, (Класс студент - ФИО, Класс предмет - название предмета, как-то переделать их??).

Как миниатюра.

введите сюда описание изображения


Ответы (1 шт):

Автор решения: vitidev

Делается это так

<DataGrid
        ItemsSource="{Binding Students, Mode=OneWay}"
        AutoGenerateColumns="True"
        AutoGeneratingColumn="OnAutoGeneratingColumn"
  1. Количество строк и так будет равно количеству элементов в списке Students

  2. AutoGenerateColumns="True" обеспечит автогенерацию колонок. Имена настраиваются так

    private void OnAutoGeneratingColumn(object? sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        string headername = e.Column.Header.ToString();
    
        //update column details when generating
        if (headername == "Name")
        {
            e.Column.Header = "First Name";
        }
    
  3. В ячейке будет то что есть в источнике. Будет в источнике пусто - значит в ячейке пусто. По умолчанию колонка будет редактируемой (ну текстовая точно). Можно подправить колонку. Она доступна как e.Column (пример выше и есть пример правки) или создать полностью свою. Это сложнее, но вот пример.

    private void OnAutoGeneratingColumn(object? sender, DataGridAutoGeneratingColumnEventArgs e)
    {
      string headername = e.Column.Header.ToString();
    
    
      if (headername == "Age")
      {
          var templateColumn = new DataGridTemplateColumn()
          {
              Header = "Student Age"
          };
    
          DataTemplate cardLayout = new DataTemplate();
          cardLayout.DataType = typeof(Student);
    
          FrameworkElementFactory spFactory = new FrameworkElementFactory(typeof(StackPanel));
          spFactory.Name = "factory";
          spFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
    
          FrameworkElementFactory cardHolder = new FrameworkElementFactory(typeof(TextBlock));
          cardHolder.SetBinding(TextBlock.TextProperty, new Binding("Age"));
          cardHolder.SetValue(TextBlock.ToolTipProperty, "Student Age");
          spFactory.AppendChild(cardHolder);
    
          cardLayout.VisualTree = spFactory;
          templateColumn.CellTemplate = cardLayout;        
          e.Column = templateColumn;
      }
    
  4. Для простоты классы должны быть плоскими вида.

    public class Student
    {
        public string Name { get; set; }
        public int Math { get; set; }
        public int Biology { get; set; }
    }
    

Если они таковыми не являются, то можно создать вьюмодель с плоским представлением.. Иначе придется переписывать биндинги в обработчике OnAutoGeneratingColumn. Ну тут кому что проще.

В общем, в OnAutoGeneratingColumn настраиваются и имена, и типы и вообще все. Также там можно отменить генерацию какой то колонки (документация)

upd: С порядком несколько сложнее. У колонки есть свойство DisplayIndex на эту тему, но я с ним дел не имел.

→ Ссылка