2

I have inherited multiple DataTables with differing column names that are all currently being displayed in their own DataGridViews. I'd like to create a new additional DataGridView that will display them all in a single DataGridView. For example (very much simplified):

public class DataTableA: DataTable
{
    public DataTableA()
    {
        this.Columns.Add("DateA", typeof(string));
        this.Columns.Add("PriceA", typeof(string));
        this.Columns.Add("SomeOtherFieldA", typeof(string));
    }
}

public class DataTableB: DataTable
{
    public DataTableB()
    {
        this.Columns.Add("DateB", typeof(string));
        this.Columns.Add("PriceB", typeof(string));
        this.Columns.Add("SomeOtherFieldB", typeof(string));
    }
}

I'd like to display values from DataTableA.DateA and DataTableB.DateB in a single column, and values from DataTableA.PriceA and DataTableB.PriceB in a single column in the new DataGridView. I've been exploring making a common base class or interface but haven't been having much luck yet. Without changing the column names (not an option), is it possible to make a binding that will be able to display both in the same column?

Edit:
Unfortunately I don't think simply merging or aggregating the DataTables into a new DataTable will work because the system was designed so that there is logic inside the DataTableX classes (for example, DataTableA and DataTableB) to handle push data and update the corresponding row in the DataTable.

Also, I'm not trying to merge rows from multiple DataTables into a single row, I'm trying to display mutliple columns with different names in a single column in the DataGridView. For example, say there was data like this:

DataTableA:

DateA       PriceA  SomeOtherFieldA
20141118    2.0      a
20141119    3.0      b

DataTableB:

DateB       PriceB  SomeOtherFieldB
20141118    4.0      c
20141119    5.0      d

I'd like to display the following in the DataGridView:

Date        Price  
20141118    2.0 
20141119    3.0 
20141118    4.0 
20141119    5.0 
JPProgrammer
  • 486
  • 8
  • 19
  • use this http://stackoverflow.com/questions/12278978/combining-n-datatables-into-a-single-datatable – Saravana Kumar Nov 17 '14 at 09:26
  • Also you can create one more class for aggregated table, that will takes DataTableA and DataTableB as parameter of constructor, and put data there as you want. – Gleb Nov 17 '14 at 09:38
  • 1
    You copy data from both datatables into a third one. You can keep the first two datatables sychronized with the third datatables by handling change events in the two first data tables. – Tarik Nov 18 '14 at 11:25
  • @Tarik - can you elaborate a little bit more on how to keep the datatables synchronized after copying the data? – JPProgrammer Nov 19 '14 at 02:12
  • You can respond to DataTable events such as RowChanged, RowDeleted and so on and refresh the third DataTable accordingly.See http://msdn.microsoft.com/en-us/library/system.data.datatable_events%28v=vs.110%29.aspx for a complete list of DataTable events. – Tarik Nov 22 '14 at 11:20

1 Answers1

0

I ended up using Tarik's tip and copying the target data from the original source tables to the destination target table, and then when the source tables are updated by push data I update the corresponding data in the target table. Below is some sample code to show how I did it.

Note: In my code I referred to the process as "reflecting" the data from the source tables to the target table, as in the target table is just showing a reflection of the source tables' data, not to be confused with object reflection, which is completely unrelated.

Copying the data:

First I made dictionaries to map the source column names to the target table column names. (The target column names are contained in a List because I needed to copy a single source column to multiple target columns - if you don't need to do that you can just use a simple string Dictionary.) For example:

Dictionary<string, List<string>> reflectedColumnsMapA = new Dictionary<string, List<string>>()
{
    { "DateA", new List<string>() { "Date" }},
    { "PriceA", new List<string>() { "Price" }},
};

Dictionary<string, List<string>> reflectedColumnsMapB = new Dictionary<string, List<string>>()
{
    { "DateB", new List<string>() { "Date" }},
    { "PriceB", new List<string>() { "Price" }},
};

Next I made a dictionary to map the original source table row to the target table row, to be used to keep the rows synchronized.

Dictionary<DataRow, DataRow> sourceToTargetRowMap = new Dictionary<DataRow, DataRow>();

Then I made a method to copy the data from a source table to the destination table, populating the source-to-target-row dictionary at the same time.

public void ReflectRowsToTable(DataTable sourceTable, DataTable targetTable, Dictionary<string, List<string>> reflectedColumnsMap)
{
    foreach (DataRow originalRow in sourceTable.Rows)
    {
        DataRow newRow = targetTable.NewRow();

        foreach (KeyValuePair<string, List<string>> keyValue in reflectedColumnsMap)
        {
            foreach (string targetColumn in keyValue.Value)
                newRow[targetColumn] = originalRow[keyValue.Key];
        }

        sourceToTargetRowMap.Add(originalRow, newRow);
        targetTable.Rows.Add(newRow);
    }
}

Keeping the data synchronized:

Finally, to keep the data synchronized I added ColumnChanged event handlers to all the source tables:

sourceTable.ColumnChanged += (s, e) =>
{
    // check if the updated column is one of the columns that were reflected
    if (reflectedColumnsMap.ContainsKey(e.Column.ColumnName))
    {
        // get the target row corresponding to the updated row in the source table
        DataRow reflectedRow = sourceToTargetRowMap[e.Row];
        // update the corresponding columns in the target table
        foreach (string targetColumn in reflectedColumnsMap[e.Column.ColumnName])
        {
            // update the value
            reflectedRow[targetColumn] = e.Row[e.Column.ColumnName];
        }
    }
};
JPProgrammer
  • 486
  • 8
  • 19