How to Avoid Explicit Casting using Generics - c#

I have a routine which converts all the data in a DataGridView to a corresponding DataTable. I want to extend this method to incorporate the ability to convert just the selected range of the DataGridView. I can clearly do this using basic logic if (bIsSelection) /*Do stuff*/ else /*Do other stuff*/ but I would like to use generics here. The problem is that the full DataGridView range is a DataGridViewColumnCollection and the selected range will be a DataGridViewSelectedColumnCollection and C# does not seem to like any conversion between the two, or allow implicit typing in the case of generics.
The first part of my code was
public static DataTable BuildDataSetFromDgv(DataGridView _dataGridView,
string strTabName)
{
DataTable dt = new DataTable();
dt.TableName = strTabName;
foreach (DataGridViewColumn col in _dataGridView.Columns)
dt.Columns.Add(col.DataPropertyName, col.ValueType);
and I have attempted
public static DataTable BuildDataSetFromDgv<T>(DataGridView _dataGridView,
string strTabName, ICollection<T> _columnColl, ICollection<T> _rowColl)
{
DataTable dt = new DataTable();
dt.TableName = strTabName;
//foreach (DataGridViewColumn col in _dataGridView.Columns)
foreach (DataGridViewColumn col in _columnColl)
dt.Columns.Add(col.DataPropertyName, col.ValueType);
which does not work due to the implicit conversion, and changing _columnColl to _columnColl as DataGridView[Selected]ColumnCollection defeats the objective.
How do I make this work with generics in this case?
Thanks for your time.

I am not sure why you need a generic one - both are collection of DataGridViewColumn. For example, why below shouldn't work for you
public static DataTable BuildDataSetFromDgv(DataGridView _dataGridView,
string strTabName, IEnumerable columns)
{
DataTable dt = new DataTable();
dt.TableName = strTabName;
var dvgColumns = columns.Cast<DataGridViewColumn>();
foreach (var col in dvgColumns)
dt.Columns.Add(col.DataPropertyName, col.ValueType);

Related

How to store values in a list or array and bind all to datatable then gridview

private void ListViewAddMethod(string fItem, string sItem, string tItem, string foItem)
{
List<ReportList> alstNames = new List<ReportList>();
alstNames.Add(new ReportList(fItem, sItem, tItem, foItem));
DataTable dt = new DataTable();
dt.Columns.Add("Particulars", typeof(string));
dt.Columns.Add("Amount", typeof(string));
dt.Columns.Add("Particulars1", typeof(string));
dt.Columns.Add("Amount1", typeof(string));
foreach (var lstNames in alstNames)
{
// Add new Row - inside the foreach loop - to enable creating new row for each object.
DataRow row = dt.NewRow();
row["Amount"] = fItem;
row["Particulars"] = sItem;
row["Particulars1"] = tItem;
row["Amount1"] = foItem;
dt.Rows.Add(row);
dgvProfitAndLoss.DataSource = alstNames;
dgvProfitAndLoss.DataBind();
}
}
This returns only the most recent row added and ignores the others. How do I create an array from parameters passed to a method and bind them to a gridview?
Your code does not look good. First, you are doing a loop over the alstNames and binding it into a gridview over each iteration of this loop. Second, you do not need a DataTable to bind it into a grid and your code you are just creating a DataTable on the heap, adding some Rows and keep it to Garbage Collector remove it, you are not even using it. Third, considering you are doing a method to add a new item on the GRidView, remove the initilization of your list to the scope of your class and keep it a valid instance (or static one if it is the case):
// declare the list output of the method
private private List<ReportList> alstNames = new List<ReportList>();
private void ListViewAddMethod(string fItem, string sItem, string tItem, string foItem)
{
// add the ReportList on the list
alstNames.Add(new ReportList(fItem, sItem, tItem, foItem));
// bind it on the gridView
dgvProfitAndLoss.DataSource = alstNames;
dgvProfitAndLoss.DataBind();
}

Adding DataRow items from collection of values

I am trying to create a DataRow which gets some values from hard-coded strings or string variables, and the rest of the values from a collection's values, System.Collections.Generic.Dictionary<string, double>.ValueCollection to be specific. In my attempt below, I'm casting to an array but that doesn't work.
DataTable source = new DataTable();
foreach (string sample in GridSource.SampleName)
{
SampleDictionaries sd = GridSource.Data.Where(x => GridSource.Data.IndexOf(x) == GridSource.SampleName.IndexOf(sample)).First();
source.Rows.Add(sample, "Average", sd.Avg.Values.ToArray());
source.Rows.Add("", "Std. Deviation", sd.StdDev.Values.ToArray());
}
The code above produces this:
I understand what is happening here. My question is this: is there an easy way to tell the DataRow "Fill the remaining column values with this collection," or am I going to have to come up with some loop to do it?
what you can do is create the row from the datatable.NewRow() method. Then you can have the items array of the row equal an array of data:
DataTable source = new DataTable();
foreach (string sample in GridSource.SampleName)
{
DataRow temp = source.NewRow();
SampleDictionaries sd = GridSource.Data.Where(x => GridSource.Data.IndexOf(x) == GridSource.SampleName.IndexOf(sample)).First();
temp.ItemArray = new object[]{sample, "Average"}.Concat(sd.Avg.Values.ToArray());
source.Rows.Add(temp);
temp = source.NewRow();
temp.ItemArray = new object[]{"", "Std. Deviation".Concat(sd.StdDev.Values.ToArray());
}
Found an answer, with help from KMoussa!
source.Rows.Add(new object[] { "", "Std. Deviation"}.Concat(sd.StdDev.Values.Cast<object>().ToArray()).ToArray());
Very similar to what he recommended, but it was missing a second cast to array at the end.

The given DataRow is not in the current DataRowCollection when tried move item from DataGridView to another

I have two DataGridView like this:
Button selected will move DataRow of DataGridView to another DataGridView.
My code like this:
public static DataRow[] GetSelectedDataRows(DataGridView grid)
{
DataRow[] dRows = new DataRow[grid.SelectedRows.Count];
for (int i = 0; i < grid.SelectedRows.Count; i++)
dRows[i] = ((DataRowView)grid.SelectedRows[i].DataBoundItem).Row;
return dRows;
}
public void MoveRows(DataTable src, DataTable dest, DataRow[] rows)
{
foreach (DataRow row in rows)
{
// add to dest
dest.Rows.Add(row.ItemArray);
// remove from src
src.Rows.Remove(row);
}
}
I use it in Event btnMoveToRight_Click().
MoveRows(dtUser, dtUserStop, GetSelectedDataRows(dgvUser));
It throws exception error like:
The given DataRow is not in the current DataRowCollection
at line:
src.Rows.Remove(row);
You can't change the Table field of a DataRow.
So you need to create a new row and also copy the data separately, maybe like this:
public void MoveRows(DataTable src, DataTable dest, DataRow[] rows)
{
foreach (DataRow row in rows)
{
// create empty row
DataRow newrow = dest.NewRow();
// copy data
newrow.ItemArray = row.ItemArray;
// add to dest
dest.Rows.Add(newrow); // (*)
// remove from src NOTE: This may or may not throw an RowNotInTableException
// to avoid it you can skip the Remove and use the loop below instead..
src.Rows.Remove(row);
}
// alternative way of removing the rows..
//foreach (DataGridViewRow item in this.dgvUser.SelectedRows)
//{
// dgvUser.Rows.RemoveAt(item.Index);
//}
}
(*) An even shorter way to clone a DataRow is using this overload of the Add method:
dest.Rows.Add(row.ItemArray);
No need for the newrow now. Note that you may want to copy the RowState from the old to the new row!? See here and here for examples of changing the RowState
If you find you need to remove the DataRows via removing the DataGridViewRows you should add the DGV to the parameters of the MoveRows function to avoid an unecessary dependence..!
Of course this assumes that the DataTables have the same structure, maybe because one is a (structural) clone of the other:
dest = src.Clone();
DataRow has a DataTable property on it (DataRow.Table).
This leads me to think that adding the row to a new table breaks the association with the old DataTable, so you don't need to call src.Rows.Remove(row).

DataColumn Name from DataRow (not DataTable)

I need to iterate the columnname and column datatype from a specific row. All of the examples I have seen have iterated an entire datatable. I want to pass a single row to a function to do a bunch of conditional processing. I want to separate the conditional processing for ease of readability.
This is what I have:
private void doMore(DataRow dr)
{
foreach (DataColumn c in dr.ItemArray) //loop through the columns.
{
MessageBox.Show(c.ColumnName.ToString());
}
}
The error returned is
System.InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Data.DataColumn'.
How would I get the column name from the row or do I have no choice and must pass the entire datatable to the function?
You would still need to go through the DataTable class. But you can do so using your DataRow instance by using the Table property.
foreach (DataColumn c in dr.Table.Columns) //loop through the columns.
{
MessageBox.Show(c.ColumnName);
}
You can make it easier in your code (if you're doing this a lot anyway) by using an extension on the DataRow object, like:
static class Extensions
{
public static string GetColumn(this DataRow Row, int Ordinal)
{
return Row.Table.Columns[Ordinal].ColumnName;
}
}
Then call it using:
string MyColumnName = MyRow.GetColumn(5);
You need something like this:
foreach(DataColumn c in dr.Table.Columns)
{
MessageBox.Show(c.ColumnName);
}
use DataTable object instead:
private void doMore(DataTable dt)
{
foreach(DataColumn dc in dt.Columns)
{
MessageBox.Show(dc.ColumnName);
}
}

ADO.NET: convert a DataTable to an array of DataRows

I'm using ADO.NET and C#, and I want to convert a DataTable object into an array of DataRows. What is an elegant way of doing this?
My first question would be why? The request makes no sense.
The answer is:
DataRow[] rows = myDataTable.Select();
Actually the DataTable has a property called Rows, witch provides the methods to do this.
You can accomplish this doing:
List<System.Data.DataRow> r = d.Rows.AsQueryable().OfType<System.Data.DataRow>().ToList();
DataTable.Select() gives you an array of DataRows. You can use this as an array
Dim dt As New DataTable
Dim dr() As DataRow = dt.Select()
In case you want an ArrayList, you can
public ArrayList ConvertDT(ref DataTable dt)
{
ArrayList converted = new ArrayList(dt.Rows.Count);
foreach (DataRow row in dt.Rows)
{
converted.Add(row);
}
return converted;
}
I have not used the dt.rows.CopyTo function. maybe that works also.
If you would like to see the contents as a string, use this code:
string.Join(",", dataTable.AsEnumerable().SelectMany(row => row.ItemArray))

Categories