Create Dynamic properties from Datatable - c#

I have below class with one property.
public class MfrYearEqpType
{
public string EqpType { get; set; }
public MfrYearEqpType()
{
}
}
I wanted to create dynamic properties(Datatable column names) to my class "MfrYearEqpType" and set the values from below Datatable.
DataTable dt = getData();
This table contains 26 rows and 10 columns of data.
I have gone through the below link. But I am not sure how to handle my case.
Dynamically adding properties to an Object from an existing static object in C#
And also I have used ExpandoObject. I have done below sample.
DataTable dt = getData();
List<dynamic> expandoList = new List<dynamic>();
foreach (DataRow row in dt.Rows)
{
//create a new ExpandoObject() at each row
var expandoDict = new ExpandoObject() as IDictionary<String, Object>;
foreach (DataColumn col in dt.Columns)
{
//put every column of this row into the new dictionary
expandoDict.Add(col.ToString(), row[col.ColumnName].ToString());
}
//add this "row" to the list
expandoList.Add(expandoDict);
}
But my aim is to create the List of MfrYearEqpType. So that I can bind List of MfrYearEqpType to Gridview.
Please help me on this.

Assuming you are talking about ASP.NET here, you can directly bind your data table to a GridView's DataSource property.
If you are happy with these 10 columns displaying as default, you can set AutoGenerateColumns property to true. Otherwise, you may want to define <asp:BoundField /> or <asp:TemplateField /> columns as appropriate. Bound fields will let you at least format the value for a particular column while template fields will allow full customization where you can provide an defining how to render a particular field.

Related

Dynamically add data to columns in GridView

I have the following code that dynamically creates columns within a WPF GridView control, the header names come from a string[] which is stored in a List<string[]> named data_org
GridView gv = tabell.View as GridView;
foreach (string s in data_org.ElementAt(0))
{
gv.Columns.Add(new GridViewColumn { Header = s });
}
Is there a way to add data while I'm creating the columns? I've searched for ways of doing it in the add column statement but can't find a way.
gv.Columns.Add(new GridViewColumn{Header = s, **statement to add data to column**});
My data is stored in another List<float[]>, where each item float[] represents a column. Do I have to do something to handle that data type (float[]), too?
You do not add data items directly to the columns of a GridView. Instead, you set the ItemsSource of the associated ListView, which is tabell in your case.
tabell.ItemsSource = /* Set a binding or assign an items collection. */;
Then you would create bindings for each column to the corresponding properties on your data items that should be displayed in the columns using DisplayMemberBinding.
var gridViewColumn = new GridViewColumn
{
Header = s,
DisplayMemberBinding = new Binding(/* Binding property path / name of the property. */);
};
As you only have a list of floats for each column, you should create a suitable data item type first. The ItemsSource expects a list of items that contain properties for each column, it represents a row.
What you have to do now is:
Create a row data type that contains properties for each column
public class MyDataItem
{
public float Number { get; }
// ...properties for other columns..
}
Create a collection of these data items with data from you float lists.
var myDataItemList = new List<MyDataItem>();
// ...create data items, add your data and add the items to the list.
Assign the list as items source of the ListView.
tabell.ItemsSource = myDataItemList;
Add display member bindings for each column.
var gridViewColumn = new GridViewColumn
{
Header = s,
DisplayMemberBinding = new Binding(nameof(MyDataItem.Number));
};
Then it should work. However, I recommend you to have a look at the MVVM design pattern.

Display rows from multiple DataTables in single DataGridView

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
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];
}
}
};

Accessing Objects used to populate DataGridView through DataTable

I am attempting to access the object that is used to fill a DataGridview in this method:
void memberDataGridView_SelectionChanged(object sender, EventArgs e)
{
foreach (DataGridViewCell cell in memberDataGridView.SelectedCells)
{
foreach (DataGridViewRow row in memberDataGridView.Rows)
{
if (row.Cells.Contains(cell))
{
//here is where I want to access the object that was used to build this row.
//it will be added as a comboboxitem
}
}
}
Here is the code of the object being added to the gridview using a DataTable
DataRow row = _loadMembersTable.NewRow();
row["Member Name"] = member.InternalLabel;
row["Type"] = member.MemberType;
_loadMembersTable.Rows.Add(row);
memberDataGridView.DataSource = _loadMembersTable;
what can I do when building the DataTable to find this member object back when I need it in the selectionChanged?
I am not sure if I understood your question properly. I think you are only assigning the object member properties to the data table columns, not the object it self. Therefore you can't directly get the object of type 'member' from the data table.
If you have a collection of members maintained in the memory then, you can query the datatable against Member Name column and get then search the collection of the members maintained in the memory.
Or you can add a new column to the DataTable of type member and then add the object to the datatable itself.
To add Column
_loadMemebersTable.Columns.Add("MemberObj",typeof(Member));
To set values
row["MemberObj"] = member;

Sort DataTable rows by length in c#

How to do following scenario:
I have some DataTable which contains for example some rows:
1.rowa
2.rowab
3.row
4.rowaba
...
n. rowabba
How to sort rows by lenght, not by name. I wan to to sort Table by length of fields.
You could add an extra column to your DataTable, supplying an expression containing a call to the len() function, causing the column's values to be automatically computed:
table.Columns.Add("LengthOfName", typeof(int), "len(Name)");
Then you can simply sort on your new column before binding the DataTable to a grid to whatever kind of UI control you plan to use:
table.DefaultView.Sort = "LengthOfName";
If you must use DataTable, you could introduce an extra column for the sort. In this case, you could set the value in the column simply to the length of each desired cell, and then sort by the new column:
DataTable table = new DataTable();
DataColumn val = table.Columns.Add("Value", typeof(string));
table.Rows.Add("abc");
table.Rows.Add("defgh");
table.Rows.Add("i");
table.Rows.Add("jklm");
// sort logic: ***** schou-rode's "len(...)" approach is better *****
DataColumn sort = table.Columns.Add("Sort", typeof(int));
foreach (DataRow row in table.Rows) {
row[sort] = ((string)row[val]).Length;
}
DataView view = new DataView(table);
view.Sort = "Sort";
foreach (DataRowView row in view) {
Console.WriteLine(row.Row[val]);
}
Personally, I'd use a typed list - of either a class, or a string in this case (since you only list one value):
List<string> list = new List<string> {
"abc", "defgh", "i", "jklm"};
list.Sort((x, y) => x.Length.CompareTo(y.Length));
foreach (string s in list) {
Console.WriteLine(s);
}

Cdd data to column series in wpf C#

I want to create a ColumnSeries Bar Chart in WPF using C#. I shall extract the data from the database and want to bind it to the bar chart.
The data extracted will contain two values. First is parameter name (string) and the other is its value (double). Which type of collection shall I use? and how to do the binding?
i finally used a simple KeyValuePair array and assigned it to the ItemsSource property of the ColumnSeries of barchart.
Just use the Dictionary as follows:
Dictionary<string,int> data = new Dictionary<string,int> ();
If you have a data in dataset then use foreach loop for item in the dataset
Example:
foreach (DataRow drv in DS.Tables[0].Rows)
{
string strvalue= Convert.ToString(drv["columnname string type"]);
string intvalue= Convert.ToString(drv["column name int type"]);
data.Add(Convert.ToString(strvalue), Convert.ToInt32(intvalue));
}
((ColumnSeries)msChart3.Series[0]).ItemsSource = data;
This way you can bind data to a column series chart type.

Categories

Resources