views:

369

answers:

2

Situation:

Hello! I am trying to populate a WPF toolkit DataGrid with a MS Access database.

Here is what I have right now (it works):

//Load the datagrid with the database
    private void LoadDataGrid(string filename, string path)
    {
        string databaseConn = "Provider=Microsoft.ACE.OLEDB.12.0;" +
                              "Data Source=" + path + "\\" + filename,
               tableName ="";
        OleDbConnection conn = null;
        DataTable schemaTable,
                  table = new DataTable();

        try
        {
            conn = new OleDbConnection(databaseConn);
            try
            {
                conn.Open();
                schemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,
                                                       new object[] { null, null, null, "TABLE" });
                tableName = "[" + schemaTable.Rows[0].ItemArray[2].ToString() + "];";
                string sqlQuery = "SELECT * FROM " + tableName;
                OleDbCommand command = new OleDbCommand(sqlQuery, conn);
                OleDbDataReader reader;
                reader = command.ExecuteReader();
                table.Load(reader);
                DataGrid_.ItemsSource = table.DefaultView;
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message); 
            }
            finally
            {
                conn.Close();
            }
        }
        catch (Exception ex)
        {
            System.Windows.MessageBox.Show(ex.Message); 
        }
    }

The code sample above loads a WPF toolkit DataGrid with the help of a MS Access database.

What I would like to do is be able to insert a column in the DataGrid at the very beginning. This column would be used to write the row number. What I think could work is to modify the table variable (which is a DataTable object).


Question:

So, how can I insert a column in the table variable, add the row number for each rows in that new column, and have all the data from the database in the DataGrid?

+2  A: 

Your easiest solution would be to modify your code to include a "virtual" RowNumber field in your original SELECT query, like so:

SELECT ROWNUM AS ROWNUMBER, * FROM TABLE1

Unfortunately, Access doesn't have anything like a ROWNUM function, so I think the easiest solution is to add a RowNumber column in the SELECT query like this:

SELECT 0 AS ROWNUMBER, * FROM TABLE1

which will add a column containing all zeroes at the beginning, and then iterate through the resulting DataTable and set the row number, like this:

int rownumber = 1;
foreach (DataRow row in table.Rows)
{
    row["ROWNUMBER"] = rownumber;
    rownumber++;
}

and then dump the DataTable into the grid.

MusiGenesis
Interesting idea. Perhaps I was looking at something too much complicated with the datatable...
Partial
I was initially going to suggest creating the ROWNUMBER DataColumn in code and doing the same thing, but there doesn't appear to be an easy way to insert a DataColumn into a specific position in the DataTable's Columns collection (as opposed to just calling Add, which puts it at the end).
MusiGenesis
I've been trying for hours to insert a column by copying the columns and rows of the DataTable but to no avail.
Partial
Your solution seems almost there, but I get an exception telling me that "ROWNUMBER" is read only...
Partial
Great, found the problem... Only need to add 1 line of code: table.Columns["ROWNUMBER"].ReadOnly = false;
Partial
Thank you MusiGenesis!
Partial
The column being read-only is not something I expected - I don't think I've ever encountered that with virtual columns from SQL Server or Oracle sources, so I'm guessing that's a by-product of the MS Access data adapter. Good detective work there.
MusiGenesis
+2  A: 

An alternative is to create a column on the DataTable before loading the IDataReader into it.


// the rest of your code
//
DataTable table = new DataTable();
DataColumn col = table.Columns.Add("RowNumber", typeof(int));
col.AutoIncrementSeed = 1;
col.AutoIncrement = true;

//
// the rest of your code
//

table.Load(reader)
//
// the rest of your code

The code snippet bellow demonstrates the technique out of the question's context


//Simulates data coming from a database or another data source
DataTable origin = new DataTable(); 
DataColumnCollection columns = origin.Columns; 
columns.Add("Id", typeof(int)); 
columns.Add("Name", typeof(string)); 
origin.Rows.Add(55, "Foo"); 
origin.Rows.Add(14, "Bar"); 
IDataReader reader = origin.CreateDataReader();

DataTable table = new DataTable(); 

//Sets up your target table to include a new column for displaying row numbers
//These are the three lines that make it all happen.
DataColumn col = table.Columns.Add("RowNumber", typeof(int)); 
col.AutoIncrementSeed = 1; 
col.AutoIncrement = true; 

//Simulates loading data from the database
table.Load(reader); 

// Examine table through the debugger. Is will have the contents of "origin" with the column "RowNumber" prepended
Alfred Myers
Loading from the reader doesn't wipe out any existing columns in the table? If not, yours is the better solution.
MusiGenesis
You can see for yourself with the following code snippet:DataTable table = new DataTable();DataColumn col = table.Columns.Add("RowNumber", typeof(int));col.AutoIncrementSeed = 1;col.AutoIncrement = true;DataTable origin = new DataTable();DataColumnCollection columns = origin.Columns;columns.Add("Id", typeof(int));columns.Add("Name", typeof(string));origin.Rows.Add(55, "Foo");origin.Rows.Add(14, "Bar");table.Load(origin.CreateDataReader());// Examine table through the debugger. Is will have the contents of "origin" with the column "RowNumber" prepended.
Alfred Myers
Oooops... I'm new here and didn't know that the code would get unformated here in the comments. The code creates another table to simulate an IDataReader through DataTable.CreateDataReader and loads this reader into the target DataTable.
Alfred Myers
It involves a bit more code but does the job. Thanks!
Partial
Actually it involves LESS code than other proposed solution.I rolled back to my original answer since MusiGenesis' edit included sample code I've put in the comments for the sole purpose of demonstrating him how it worked.If you guys think that the demonstration is valid, feel free to add the sample code back (or ask me to do so) BUT make it clear that it only demonstrates the concept and it not needed for the code in Partial's question.
Alfred Myers
You can put it back. It is absolutely relevant!
Partial