使用嵌套列表和动态列填充 DataGrid

Filling DataGrid using nested lists and dynamic columns

我有一个奇怪的数据模型,我正在尝试在数据网格中生成动态列并正确绑定项目。

我有一个要绑定到 DataGrid 并使用简单的 DataGridTextColumn 显示的 Row 对象列表。

<controls:DataGrid
   Grid.Row="1"
   x:Name="dataGrid"
   ItemsSource="{x:Bind ViewModel.CurrentRows}"

我的 objective 是从第一行获取列列表并在设置绑定时构建我的网格列。我无法找出在 RowValue.value.

处绑定数据的正确方法
public TablePage()
{
    InitializeComponent();

    dataGrid.ItemsSource = ViewModel.CurrentRows;

    foreach (Column column in ViewModel.CurrentRows.FirstOrDefault().Values.Select(x => x.key))
    {
        dataGrid.Columns.Add(new DataGridTextColumn()
        {
            Header = column.ColumnValidation.column_label,
            Binding = new Binding() { Path = new PropertyPath("Values.value") }
        });
    }
}

在我的视图模型中我有:

public ObservableCollection<Row> CurrentRows

Row 对象如下所示:

public class Row: INotifyPropertyChanged
{
    public List<RowValue> Values { get; set; } = new List<RowValue>();

    public event PropertyChangedEventHandler PropertyChanged;
}

最后一个 RowValue 对象如下所示:

public class RowValue: INotifyPropertyChanged
{
    public Column key { get; set; }
    public string value { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
}

列如下所示:

public class Column
{
    public string name;
    public ColumnValidation ColumnValidation;
}

ColumnValidation 看起来像这样:

public class ColumnValidation
{
    public string column_label;
    public DataTypeEnum data_type;
    public int width;
    public int decimal_places;
    public int display_order;
    public string calculation_formula;
    public string edit_style;
    public string default_value;
    public decimal? minimum_value;
    public decimal? maximum_value;
    public bool is_column_nullable = false;
    public bool inherit_values = false;
    public bool display_column = false;
    public bool is_editable = false;
    public int column_style;
    public string code_table_name;
    public string code_display_name;
    public string code_data_column_name;
}

我的解决方案最终是使用我的列定义列表和行数据构建一个 DataTable。这是一个非常肮脏的解决方案,但它适合我的目的。我没有对网格进行任何编辑或保存,它只是用于显示数据。编辑发生在别处的对话框中。

public TablePage()
{
    InitializeComponent();

    // get list of columns
    List<Column> columns = ViewModel.CurrentTableDefinition.Columns.OrderBy(x => x.ColumnValidation.display_order).ToList();

    // create DataTable
    DataTable dataTable = new DataTable();
    dataTable.Columns.Add(new DataColumn() { ColumnName = "RowObject" }); // add column to store original row object

    // add columns to datagrid and datatable
    for (int i = 0; i < columns.Count; i++)
    {
        // add column to datagrid using the correct header label. bind using index of array.
        dataGrid.Columns.Add(new DataGridTextColumn()
        {
            Header = columns[i].ColumnValidation.column_label,
            Tag = columns[i].name,
            Binding = new Binding() { Path = new PropertyPath("[" + i.ToString() + "]") }
        });

        // add corresponding column to datatable
        dataTable.Columns.Add(new DataColumn() { ColumnName = columns[i].name });
    }

    // iterate through rows of data
    foreach (Row row in ViewModel.CurrentRows)
    {
        // create new datatable row
        DataRow dataRow = dataTable.NewRow();

        // set the original row object 
        dataRow["RowObject"] = row;

        // add data from each column in the row to the datatable row
        for (int i = 0; i < columns.Count; i++)
        {
            // add column value to row
            try
            {
                dataRow[i] = row.Values.Where(x => x.key.name == columns[i].name).FirstOrDefault().value;
            }
            
            catch (Exception ex)
            {
                dataRow[i] = null; // insert null if the table has columns defined for which there is no data in the dataset
            }
        }

        // add datable row to datatable
        dataTable.Rows.Add(dataRow);
    }

    // convert datatable to collection of 'object'
    ObservableCollection<object> collection = new ObservableCollection<object>();

    foreach(DataRow row in dataTable.Rows)
        collection.Add(row.ItemArray);

    // bind to datagrid
    dataGrid.ItemsSource = collection;
}