I'm using datatable that has two columns of text data, I just want to do abbreviations expanding for each row, so I used Dictionary and here it is a sample of my code:
private void ExpandWords()
{
DataTable DT = new DataTable();
DataRow Row;
DT.Columns.Add(new System.Data.DataColumn("Name", typeof(string)));
DT.Columns.Add(new System.Data.DataColumn("Label", typeof(string)));
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("emp", "employee");
dict.Add("dep", "department");
for (int i = 0; i < dataGridView6.Rows.Count; i++)
{
Row = DT.NewRow();
foreach(KeyValuePair<string,string> rep in dict)
{
Row[0] = dataGridView6.Rows[i].Cells[0].Value.ToString().Replace (rep.Key, rep.Value);
Row[1] = dataGridView6.Rows[i].Cells[1].Value.ToString().Replace (rep.Key, rep.Value);
}
DT.Rows.Add(Row);
dataGridView7.DataSource = DT;
}
it can be run without exceptions but it doesn't work
Why do you enumerate the dictionary in the loop of the grid-rows? Just lookup the key.
You also have to add each row in the loop, not outside, otherwise you just add the last row:
for (int i = 0; i < dataGridView6.Rows.Count; i++)
{
Row = DT.NewRow();
string abbrCell1 = dataGridView6.Rows[i].Cells[0].Value.ToString();
string abbrCell2 = dataGridView6.Rows[i].Cells[1].Value.ToString();
Row[0] = dict[abbrCell1];
Row[1] = dict[abbrCell2];
DT.Rows.Add(Row);
}
Edit If you want to replace all abbreviated words in the string of the datagrid cells with the not-abbreviated word in the dictionary you can use this code:
// in the loop
Row = DT.NewRow();
string abbrCell1 = dataGridView6.Rows[i].Cells[0].Value.ToString();
string abbrCell2 = dataGridView6.Rows[i].Cells[1].Value.ToString();
IEnumerable<string> unabbrWords1 = abbrCell1.Split()
.Select(w => dict.ContainsKey(w) ? dict[w] : w);
IEnumerable<string> unabbrWords2 = abbrCell2.Split()
.Select(w => dict.ContainsKey(w) ? dict[w] : w);
Row[0] = string.Join(" ", unabbrWords1);
Row[1] = string.Join(" ", unabbrWords2);
DT.Rows.Add(Row);
You should change it a bit otherwise you'll have same value overwritten in loop:
var value1 = dataGridView6.Rows[i].Cells[0].Value.ToString();
var value2 = dataGridView6.Rows[i].Cells[1].Value.ToString();
foreach (KeyValuePair<string, string> rep in dict)
{
value1 = value1.Replace(rep.Key, rep.Value);
value2 = value2.Replace(rep.Key, rep.Value);
}
DT.Rows.Add(value1, value2);
You're also missing DataBind() if you're using Web Forms at the end
dataGridView7.DataSource = DT;
dataGridView7.DataBind();
mz
Related
I have a DataTables with Emails. Over the LDAP I have the Userdata. Now Id like to Increase the DataTable depending upon the EmailAdress.
myDataTable.Columns.Add(new DataColumn("LDAP_Data"));
foreach(DataRow row in modiTable.Rows)
{
string myLDAPData = DoLDAPAction(row.Field<string>("EMAIL"));
//how to insert to myDataTable > LDAP_Data
}
how can I insert the new Data from LDAP to the new Column?
Thanks
If you add a row to a DataTable you have to add a row which columns match you table. This is why you get back a row if you call DataTable.Add().
Here an example how to add new rows:
static void Main(string[] args)
{
DataTable dt = new DataTable(); // Create a example-DataTable
dt.Columns.Add(new DataColumn() { ColumnName = "Name", DataType = typeof(string) }); // Add some columns
dt.Columns.Add(new DataColumn() { ColumnName = "Id", DataType = typeof(int) });
// Let's fill the table with some rows
for (int i = 0; i < 20; i++) // Add 20 Rows
{
DataRow row = dt.Rows.Add(); // Generate a row
row["Id"] = i; // Fill in some data to the row. We can access the columns which we added.
row["Name"] = i.ToString();
}
// Let's see what we got.
for (int i = 0; i < dt.Columns.Count; i++) // Loop through all columns
{
Console.Write(dt.Columns[i].ColumnName + ";"); // Write the ColunName to the console with a ';' a seperator.
}
Console.WriteLine();
foreach (DataRow r in dt.Rows) // Generic looping through DataTable
{
for (int i = 0; i < dt.Columns.Count; i++) // Loop through all columns
{
Console.Write(r[i] + ";");
}
Console.WriteLine();
}
}
You can do it by using the NewRow method:
foreach(DataRow row in modiTable.Rows)
{
string myLDAPData = DoLDAPAction(row.Field<string>("EMAIL"));
DataRow row = modiTable.NewRow();
row["EMAIL"] = myLDAPData;
//You might want to specify other values as well
}
Or you can use the Add() method, as suggested in kara's answer.
myDataTable.Columns.Add(new DataColumn("LDAP_Data"));
foreach(DataRow row in modiTable.Rows)
{
string myLDAPData = DoLDAPAction(row.Field<string>("EMAIL"));
var row = myDataTable.NewRow()
row["LDAP_Data"] = YOUR_DATA;
myDataTable.Rows.Add(row);
}
This is going to be my text file (30 lines)
OrderNo:37374
OrderQuantity:250
BarcodeQR:584,25478Klkd28
NormalBarcode:1565484864
.......
.......
.......
This is the code :
public DataTable DTforReport()
{
DataTable dt = new DataTable();
DataColumn col = new DataColumn("test");
col.DataType = System.Type.GetType("System.String");
dt.Columns.Add(col);
string[] lines = File.ReadAllLines("C:\\Users\\abc\\Desktop\\abc.txt");
foreach (var line in lines)
{
var segments = line.Split(';');
foreach (var seg in segments)
{
DataRow dr = dt.NewRow();
dr[0] = seg;
dt.Rows.Add(dr);
}
}
return dt;
}
I want my output like this
OrderNo OrderQuantity BarcodeQR
37374 250 584,25478Klkd28
How can I change my code to achieve this?
You have generated only one column. Change your code like below to see your desired result:
public DataTable DTforReport()
{
DataTable dt = new DataTable();
string[] lines = File.ReadAllLines("C:\\Users\\abc\\Desktop\\abc.txt");
DataRow dr = dt.NewRow();
for (int i = 0; i < lines.Length; i++)
{
DataColumn col = new DataColumn(lines[i].Split(':')[0]);
col.DataType = Type.GetType("System.String");
dt.Columns.Add(col);
var segment = lines[i].Split(':')[1];
dr[i] = segment;
}
dt.Rows.Add(dr);
return dt;
}
I suggest you to modify your method like the following:
public DataTable DTforReport()
{
DataTable testTable = new DataTable("Test");
testTable.Columns.Add("OrderNo");
testTable.Columns.Add("OrderQuantity");
testTable.Columns.Add("BarcodeQR");
string[] lines = File.ReadAllLines("C:\\Users\\abc\\Desktop\\abc.txt");
foreach (var line in lines)
{
DataRow dRow = testTable.NewRow();
var segments = line.Split(';');
for (int i = 0; i < segments.Length; i++)
{
var colValues = segments[i].Split(':');
dRow[i] = colValues[1];
}
testTable.Rows.Add(dRow);
}
return testTable;
}
Few suggestions for improvement:
I have given static column names, if you want to add more or they may change in future means you can create dynamic columns in the datatable.
If you have doubts in the input values, make use of proper validation
Validations in the sense, make sure about the splitted values before accessing them through index otherwise they may ends up with IndexOutOfRangeException
DataTable dt = new DataTable();
string[] lines = File.ReadAllLines("C:\\Users\\abc\\Desktop\\abc.txt");
var firstLine = lines.First();
var columns = firstLine.Split(';');
for (var icount = 0; icount < columns.Count(); icount++)
{
var colName = columns[icount].Contains(":") ? columns[icount].Split(':')[0] : "Column" + icount;
var dataCol = new DataColumn(colName);
dataCol.DataType = System.Type.GetType("System.String");
dt.Columns.Add(dataCol);
}
foreach (var line in lines)
{
DataRow dr = dt.NewRow();
var segments = line.Split(';');
for (var icount = 0; icount < segments.Count(); icount++)
{
var colVal = segments[icount].Contains(":") ? segments[icount].Split(':')[1] : "";
dr[icount] = colVal;
}
dt.Rows.Add(dr);
}
*Number of column must be same in each row.
In normal WinForm application you can do that:
DataTable dataTable = new DataTable();
dataTable = dataGridRecords.DataSource;
but how to do that with the WPF datagrid?
dataTable = dataGridRecords.ItemsSource;
won't work either.
In WPF you don't do this
DataGrid.ItemsSource = DataTable;
Instead you do
DataGrid.ItemsSource = DataTable.AsDataView();
In order to get DataTable back you can do something like this
public static DataTable DataViewAsDataTable(DataView dv)
{
DataTable dt = dv.Table.Clone();
foreach (DataRowView drv in dv)
dt.ImportRow(drv.Row);
return dt;
}
DataView view = (DataView) dataGrid.ItemsSource;
DataTable table = DataViewAsDataTable(view)
You don't need the DataViewAsDataTable method. Just do the following:
DataTable dt = ((DataView)dataGrid1.ItemsSource).ToTable();
try this
public static DataTable DataGridtoDataTable(DataGrid dg)
{
dg.SelectAllCells();
dg.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader;
ApplicationCommands.Copy.Execute(null, dg);
dg.UnselectAllCells();
String result = (string)Clipboard.GetData(DataFormats.CommaSeparatedValue);
string[] Lines = result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
string[] Fields;
Fields = Lines[0].Split(new char[] { ',' });
int Cols = Fields.GetLength(0);
DataTable dt = new DataTable();
for (int i = 0; i < Cols; i++)
dt.Columns.Add(Fields[i].ToUpper(), typeof(string));
DataRow Row;
for (int i = 1; i < Lines.GetLength(0)-1; i++)
{
Fields = Lines[i].Split(new char[] { ',' });
Row = dt.NewRow();
for (int f = 0; f < Cols; f++)
{
Row[f] = Fields[f];
}
dt.Rows.Add(Row);
}
return dt;
}
I have a datatable with 10 columns, but User can select the columns to be displayed so I need to create a generic code to display only the selected columns.
Current code:
string[] selectedColumns = new[] { };
DataTable columns = new DataView(table).ToTable(false, selectedColumns);
You could simply hide the columns in the datagridview (supposing you're using one)
dataGridView1.Columns["ColName"].Visible = False;
for every column that are not in selectedColumns
But if you really need to filter the dataset, I remember that you can do something like:
mydatatable.Columns.Remove("ColName");
in your datatable... or in a copy.
If you are going to show the columns in a datagridview, my option will be setting the ColumnMapping property of the datatable column like this
mydatatable.Columns["Colname"].ColumnMapping = MappingType.Hidden;
Unfortunatly I'm not at home now, so I can't test it, but as you can see, there are many options.
EDIT: In response to your request, you can deal with non selected columns like this:
for(int i = 0;i<dt.Columns.Count;i++)
{
if(!selectedColumns.Contains(dt.Columns[i].ColumnName))
{
dt.Columns[i].ColumnMapping = MappingType.Hidden;
}
}
public static void Main(string[] args)
{
DataTable act = new DataTable();
act.Columns.Add(new DataColumn("id", typeof(System.Int32)));
act.Columns.Add(new DataColumn("name"));
act.Columns.Add(new DataColumn("email"));
act.Columns.Add(new DataColumn("phone"));
DataRow dr = act.NewRow();
dr["id"] = 101;
dr["name"] = "Rama";
dr["email"] = "rama#mail.com";
dr["phone"] = "0000000001";
act.Rows.Add(dr);
dr = act.NewRow();
dr["id"] = 102;
dr["name"] = "Talla";
dr["email"] = "talla#mail.com";
dr["phone"] = "0000000002";
act.Rows.Add(dr);
dr = act.NewRow();
dr["id"] = 103;
dr["name"] = "Robert";
dr["email"] = "robert#mail.com";
dr["phone"] = "0000000003";
act.Rows.Add(dr);
dr = act.NewRow();
dr["id"] = 104;
dr["name"] = "Kevin";
dr["email"] = "kevin#mail.com";
dr["phone"] = "0000000004";
act.Rows.Add(dr);
dr = act.NewRow();
dr["id"] = 106;
dr["name"] = "TomChen";
dr["email"] = "tomchen#mail.com";
dr["phone"] = "0000000005";
act.Rows.Add(dr);
var lselColumns = new[] {"id", "name"};
var dt = act.DefaultView.ToTable(true, lselColumns);
foreach (DataRow drow in dt.Rows)
{
string drowData = string.Empty;
foreach (DataColumn r in drow.Table.Columns)
{
drowData += (drowData == string.Empty) ? drow[r] : "|" + drow[r];
}
Console.WriteLine(drowData);
}
Console.ReadLine();
}
I am looping through a datatable and currently I do
string customerId = row["CustomerId"].ToString();
string companyName = row["Company Name"].ToString();
Instead of declaring every variable how do I add these do a dictionary?
I was thinking something like:
foreach (DataRow row in customerTbl.Rows)
{
Dictionary<string, string> customerDictionary = new Dictionary<string, string>();
customerDictionary.Add(row[].ToString(), row[].ToString());
so yeah, how do I get the row name and value into there?
Thanks in advance.
EDIT:
I guess I didn't give you all information about what I am trying to do.
I query a database for a customer and populate a datatable with about 50 columns, I use the customer id to query another database and get the same customer from there. I then want to compare all 50 fields from both databases for the same customer and check if any field is different. I thought I could add the column name with the value in a dictionary for each row for each customer and then with two loops check if the values for the same key (column name) differs, is this a totally wrong approach?
having an if (customerId1 != customerId2 || customerName1 != customerName2 || and so on for 50 fields is not very good.
Are you looking for a generic solution to this kind of thing? If so does your DataTable always contain 2 columns where the first can be treated as the dictionary key and the second the value? If so, then simply use the column index instead of the column name
var customerDictionary = new Dictionary<string, string>();
foreach (DataRow row in customerTbl.Rows)
customerDictionary.Add(row[0].ToString(), row[1].ToString());
If the values in the customerId and CompanyName columns are never null then instead of using ToString(), you can cast the values to a string
customerDictionary.Add((string)row[0], (string)row[1]);
FYI, the DataTable has a search capability as well (the Find() method). If you set up a primary key column the search will be extremely fast and you may not need to copy the data from a DataTable to a Dictionary.
Edit : A complete working example of one way of doing this in C# code as per the OPs edited question
class Program
{
static void Main(string[] args)
{
var table1 = GetCustomersFromFirst();
var table2 = GetCustomersFromSecond();
foreach (DataRow row in table1.Rows)
{
var foundRows = table2.Select("CustomerId = " + (string)row[0]);
if (foundRows.Length == 1)
{
var foundRow = foundRows[0];
foreach (DataColumn col in table1.Columns)
{
var valueOfColumnFromTable1 = row[col.Ordinal].ToString();
var valueOfColumnFromTable2 = foundRow[col.Ordinal].ToString();
if (String.Compare(valueOfColumnFromTable1, valueOfColumnFromTable2) != 0)
{
//the colum values are not the same.
}
}
}
else
{
// Something is wrong since more than one matching record was found
// or no matching records were found.
}
}
}
static DataTable GetCustomersFromFirst()
{
var dt = GetInitializedCustomerDataTable();
var row = dt.NewRow();
row[0] = "1";
row[1] = "CompanyA";
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = "2";
row[1] = "CompanyB";
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = "3";
row[1] = "CompanyC";
dt.Rows.Add(row);
return dt;
}
static DataTable GetCustomersFromSecond()
{
var dt = GetInitializedCustomerDataTable();
var row = dt.NewRow();
row[0] = "1";
row[1] = "CompanyA";
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = "2";
row[1] = "CompanyD";
dt.Rows.Add(row);
row = dt.NewRow();
row[0] = "3";
row[1] = "CompanyC";
dt.Rows.Add(row);
return dt;
}
static DataTable GetInitializedCustomerDataTable()
{
var dt = new DataTable();
dt.Columns.Add("CustomerId", typeof(string));
dt.Columns.Add("CompanyName", typeof(string));
return dt;
}
}
In the test data, the 2nd row does not match. So it should fall into the condition where the comment says:
//the colum values are not the same.
Personally, I'd look at doing this in the database itself.
Try this.
Dictionary<string, string> customerDictionary = new Dictionary<string, string>();
foreach (DataRow row in customerTbl.Rows)
{
if(row["CustomerId"] != null && customerDictionay.ContainsKey("CustomerId") == false)
{
customerDictionary.Add(row["CustomerID"].ToString(), row["CompanyName"] as string);
}
}
Just a question, what's the benefit of putting the values in a dictionary? You are basically just eliminating the need of writing .ToString() when accessing the values...i.e, instead of:
row["CustomerID"].ToString();
you write
customerDictionary["CustomerID"];
Or have I missed something?