Fill DataTable with objects from memory and display the results in a DataGridView control. This will allow you to build a DataTable in a separate class and then simply assign the DataGridView's DataSource to it, providing more code separation of display and logic. You will not interact with a database here, but will instead use data in Lists and arrays.
We are using Windows Forms and must put a DataGridView in our form. For the rest of the solution, we will use this DataGridView. First, our example here will put thousands (even millions) of numbers in a DataTable which is frequently updated. (This could be used for many interesting things, including robotics.)
Good question. You could manually add data to the DataGridView using the Add method, but I wanted a solution that would put the logic for building the table in a separate class, not on the UI thread. This also would allow multithreading. In my experience, DataGridView has severe performance problems with manually adding rows. Assiging to the DataSource is far faster (often).
We want to make a new class and make a method that returns DataTable. This method will return the fully constructed DataTable which will be simply assigned to the DataGridView. This will be fast. In my testing the application handled 1,000,000 numbers with only moderate slowdowns.
public DataTable GetResultsTable()
{
// 1.
// Create the output table.
DataTable outTable = new DataTable();
// 2.
// Loop through all process names.
for (int i = 0; i < this._dataArray.Length; i++)
{
// 3.
// The current process name.
string name = this._names[i];
// Add the program name to our columns.
outTable.Columns.Add(name);
// 4.
// Add all of the memory numbers to an object list.
List<object> objectNumbers = new List<object>();
// Put every column's numbers in this List.
foreach (double number in this._dataArray[i])
{
objectNumbers.Add((object)number);
}
// 5.
// Keep adding rows until we have enough.
while (outTable.Rows.Count < objectNumbers.Count)
{
outTable.Rows.Add();
}
// 6.
// Add each item to the cells in the column.
for (int a = 0; a < objectNumbers.Count; a++)
{
outTable.Rows[a][i] = objectNumbers[a];
}
}
return outTable;
}
In the above code, we allocate (create) a new DataTable. This is what will eventually be populated with all the data and put into the DataGrid. (There are more efficient ways of modifiying an existing DataTable.)
We have an array that contains many arrays. Each of those arrays it contains needs to be a new column. So the main loop in the above code loops through the data we want to put in each column, one column at a time.
In step 3 we add the column names to the DataTable. This can be the data series type (such as "name", "number", "id", or process name). These are the column headers, which must be added with .Columns.Add(). They will automatically appear as column headers.
The DataTable requires that we use arrays of objects to assign to the cells. This is inconvenient, but not too bad. (It will require boxing and unboxing.) In step 4 we loop through each point in the column, which each point being a new row. Once we are done with that, we move to step 5.
Why must we add empty rows? In step 5 we keep adding rows until we have enough to contain all the data points in our array. If we don't add empty rows, the runtime will throw an exception and the DataTable will be invalid. Right after this step, we assign the cells (whether the rows are new or not).
In step 6, we set each cell in this column to its data value. The rows will already exist because of step 5. Be careful with the indexer syntax on the DataTable and it is important that there is enough rows. We will directly use our object list that we converted from another value type, as DataTable won't accept arbitrary types (in my testing).
By assigning the DataSource of your DataGridView directly to the result value of the method above. This will populate all the cells "magically". What we are doing is using .NET's built-in display logic instead of "reinventing the wheel." Here's how you might assign the DataSource.
// Draw new cells on DataGridView. dataGridView1.DataSource = null; dataGridView1.DataSource = _example.GetResultsTable();
This style of code was used in my Memory Watcher application, which was effective in storing 1+ million data points and rendering them every 3 seconds. Using a DataTable is far smoother for Windows Forms than manually adding rows, and also allows you to separate presentation from logic. It also requires less code.
My program Memory Watcher uses this exact style of code, and it is where I adapted this article. It is available at my Google Code site which is linked to at the bottom of each page. It has been downloaded over 1,000 times and no one has sent me an angry email about it.