I'm new to programming (1st year of learning at college) and I'm working on a small application.
I have a window where user can retrieve data from SQL to DataGrid and a Button for exporting some data from a DataGrid data to a text file.
This is the code I've used to get data from SQL:
SqlConnection con = new SqlConnection("Server = localhost;Database = autoser; Integrated Security = true");
SqlCommand cmd = new SqlCommand("selectproduct", con); // Using a Store Procedure.
cmd.CommandType = CommandType.StoredProcedure;
DataTable dt = new DataTable("dtList");
cmd.Parameters.AddWithValue("#Code", txtbarcode.Text);
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
data.ItemsSource = dt.DefaultView;
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
adapt.Fill(ds);
con.Close();
int count = ds.Tables[0].Rows.Count;
if (count == 0)
{
MessageBox.Show("This product doesn't excist");
SystemSounds.Hand.Play();
}
else if (count == 1)
{
lblinfo.Visibility = Visibility.Visible;
SystemSounds.Asterisk.Play();
}
And this one is the code I used to write text file:
{
using (StreamWriter writer = new StreamWriter("D:\\test.txt", true))
{
writer.WriteLine("Welcome");
writer.WriteLine("E N T E R N E T");
}
using (StreamWriter writer = new StreamWriter("D:\\test.txt", true))
{
writer.WriteLine(data.Items);
}
using (StreamWriter writer = new StreamWriter("D:\\test.txt", true))
{
writer.WriteLine(data.Items);
}
// Append line to the file.
using (StreamWriter writer = new StreamWriter("D:\\test.txt", true))
{
writer.WriteLine("---------------------------------------");
writer.WriteLine(" Thank You! ");
writer.WriteLine(" " + DateTime.Now + " ");
}
}
When I Open the text file i get this data
Welcome
E N T E R N E T
System.Windows.Controls.ItemCollection - Why isn't show the data grid
data
---------------------------------------
Thank You
7/26/2018 12:38:37 PM
My question is: Where is my mistake that cause the data from the DataGrid to don't be showed in correct way?
Thanks in advance
You are using currently the following overload of the WriteLine method:
public virtual void WriteLine(object value)
If you look at the documentation of StreamWriter.WriteLine(object) it says that it:
Writes the text representation of an object by calling the ToString method on that object, followed by a line terminator to the text string or stream.
This is the reason why you get the following nice line in your file:
System.Windows.Controls.ItemCollection
The documentation of Object.ToString() method reveals that the
default implementations of the Object.ToString method return the fully qualified name of the object's type.
You would need to iterate through the collection and write each entry separately into the file. I would also suggest to use directly the data source instead of writing from the DataGrid.
foreach (DataRow row in dt.Rows)
{
object[] array = row.ItemArray;
writer.WriteLine(string.Join(" | ", array));
}
This is because data.Items is an ItemCollection and not a string.
All objects return the output of their ToString method when are asked to represent their contents as string. Normally you would override this method but in this case you can't.
So you need to tell the compiler how to retrieve the representative information from that collection. You can use either of these queries to fetch desired information out of the data grid:
var items = data.Items.AsQueryable().Cast<MyItemDataType>().Select(x => x.MyProperty);
var items = data.ItemsSource.Cast<MyItemDataType>().Select(x => x.MyProperty);
var items = data.Items.SourceCollection.AsQueryable().Cast<MyItemDataType>().Select(x => x.MyProperty);
items is a collection so you need to convert it to a string:
var text = items.Aggregate((x,y)=> x+", "+y);
MyItemDataType differs in each query and you have to find out yourself which data type is being used and MyProperty is the property in that class which represents the text of a row.
Edit
You can use this code too. It does the same thing:
string text = "";
for (int i = 0; i < data.Items.Count; i++)
{
text += data.Items[i].ToString();
if(i < data.Items.Count - 1)
text += ", ";
}
writer.WriteLine(text);
But pay attention to the data type of each item in data.Items[i].ToString(). For example if each item is of type int then data.Items[i].ToString() returns a string representing the value of that integer (e.g. 1 turns into "1") but if they are of other types (e.g. such as Customer or MyDataGridItem) you need to override ToString() method of that class to look something like this:
public class Customer{
//...
public override string ToString(){
return this.Id + " " + this.Name;
}
}
so if you cannot override this method for any reason you need to do the other approach:
string text = "";
for (int i = 0; i < data.Items.Count; i++)
{
Customer customer = data.Items[i] as Customer;//cast is required since type of Items[i] is object
text += (customer.Id + " " + customer.Name);
if(i < data.Items.Count - 1)
text += ", ";
}
writer.WriteLine(text);
furthermore, you can use a StringBuilder to speed up the string concatenation because += is slow on strings.
Look at the sample code here. This will do what you want.
public static void WriteDataToFile(DataTable submittedDataTable, string submittedFilePath)
{
int i = 0;
StreamWriter sw = null;
sw = new StreamWriter(submittedFilePath, false);
for (i = 0; i < submittedDataTable.Columns.Count - 1; i++)
{
sw.Write(submittedDataTable.Columns[i].ColumnName + ";");
}
sw.Write(submittedDataTable.Columns[i].ColumnName);
sw.WriteLine();
foreach (DataRow row in submittedDataTable.Rows)
{
object[] array = row.ItemArray;
for (i = 0; i < array.Length - 1; i++)
{
sw.Write(array[i].ToString() + ";");
}
sw.Write(array[i].ToString());
sw.WriteLine();
}
sw.Close();
}
Also, take a look at this.
using System;
using System.Web;
using System.IO;
using System.Data;
namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
StreamWriter swExtLogFile = new StreamWriter("D:/Log/log.txt",true);
DataTable dt = new DataTable();
//Adding data To DataTable
dt.Columns.Add("ID");
dt.Columns.Add("Name");
dt.Columns.Add("Address");
dt.Rows.Add(1, "venki","Chennai");
dt.Rows.Add(2, "Hanu","London");
dt.Rows.Add(3, "john","Swiss");
int i;
swExtLogFile.Write(Environment.NewLine);
foreach (DataRow row in dt.Rows)
{
object[] array = row.ItemArray;
for (i = 0; i < array.Length - 1; i++)
{
swExtLogFile.Write(array[i].ToString() + " | ");
}
swExtLogFile.WriteLine(array[i].ToString());
}
swExtLogFile.Write("*****END OF DATA****"+DateTime.Now.ToString());
swExtLogFile.Flush();
swExtLogFile.Close();
}
}
}
Related
I am currently making a Windows form in Visual Studio 2017.
I have the DataGridView displaying the data from the CSV correctly.
The problem is when the user inputs some data and saves it and then looks at the DataGridView the data doesn't contain the new data until the program is closed and opened again.
So when the user presses the button Save as Preset the csv is updated however the data in the DataGridView is not.
I have searched the web and can't find any solutions and have tried the usual PresetView.Refresh(); and PresetView.Update(); but is seems that that doesn't fix many people problems either.
Button Code:
public void ButtonProperties()
{
SaveCustomPreset.Click += new EventHandler(SaveCustomPreset_Click);
}
Writing to CSV code:
private void DisplayPresetData(string filePath)
{
DataTable dt = new DataTable();
string[] csv_data = System.IO.File.ReadAllLines(filePath);
string[] data_col = null;
int x = 0;
foreach (string text_line in csv_data)
{
data_col = text_line.Split(',');
if(x == 0)
{
for(int i = 0; i <= data_col.Count() -1; i++)
{
dt.Columns.Add(data_col[i]);
}
x++;
}
else
{
dt.Rows.Add(data_col);
}
}
PresetView.DataSource = dt;
}
Button click code:
private void SaveCustomPreset_Click(object sender, EventArgs e)
{
TextWriter txt = new StreamWriter("../../PresetData.csv", true);
txt.WriteLine(CustomPresetName.Text + "," + CustomX.Text + "," + CustomY.Text + "," + CustomZ.Text + "," + Foam.Text);
txt.Close();
PresetView.Refresh();
PresetView.Update();
}
In your code sample, you're creating a new instance of a DataTable type, and then assigning it to your control as a datasource.
thus, your control's datasource is that object instance that was created in that scope.
private void DisplayPresetData(string filePath)
{
DataTable dt = new DataTable();
string[] csv_data = System.IO.File.ReadAllLines(filePath);
string[] data_col = null;
int x = 0;
foreach (string text_line in csv_data)
{
data_col = text_line.Split(',');
if(x == 0)
{
for(int i = 0; i <= data_col.Count() -1; i++)
{
dt.Columns.Add(data_col[i]);
}
x++;
}
else
{
dt.Rows.Add(data_col);
}
}
PresetView.DataSource = dt;
}
Refreshing the control is not going to automatically call this method.
You can do a couple things to handle this:
You can cast the DataSource (which is actually a DataTable type) to DataTable and Add data to it in the SaveCustomPreset EventHandler method scope.
private void SaveCustomPreset_Click(object sender, EventArgs e)
{
var columns = new []
{
CustomPresetName.Text,
CustomX.Text,
CustomY.Text,
CustomZ.Text,
Foam.Text
};
var line = string.Join(",", columns);
using (TextWriter txt = new StreamWriter("../../PresetData.csv", true))
{
txt.WriteLine(line);
}
var dt = (DataTable)PresetView.DataSource;
foreach(var item in columns)
{
dt.Rows.Add(item)
}
}
or, you can call to the DisplayPresetData(string filePath) method in that event handler (or a similar method that reads data off the file and assigns it to PresetView.DataSource)
The benefit of the second implementation is that you can account for modifications on the csv from scenarios outside of your writing to it.
The benefit of the first implementation is performance. (that is, you avoid the stream file reading, buffering, and looping operations in that method, and instead, you would do incremental Adds.)
i am currently working on a small Project and i got stuck with a Problem i currently can not manage to solve...
I have multiple ".CSV" Files i want to read, they all have the same Data just with different Values.
Header1;Value1;Info1
Header2;Value2;Info2
Header3;Value3;Info3
While reading the first File i Need to Create the Headers. The Problem is they are not splited in Columns but in rows (as you can see above Header1-Header3).
Then it Needs to read the Value 1 - Value 3 (they are listed in the 2nd Column) and on top of that i Need to create another Header -> Header4 with the data of "Info2" which is always placed in Column 3 and Row 2 (the other values of Column 3 i can ignore).
So the Outcome after the first File should look like this:
Header1;Header2;Header3;Header4;
Value1;Value2;Value3;Info2;
And after multiple files it sohuld be like this:
Header1;Header2;Header3;Header4;
Value1;Value2;Value3;Value4;
Value1b;Value2b;Value3b;Value4b;
Value1c;Value2c;Value3c;Value4c;
I tried it with OleDB but i get the Error "missing ISAM" which i cant mange to fix. The Code i Used is the following:
public DataTable ReadCsv(string fileName)
{
DataTable dt = new DataTable("Data");
/* using (OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"" +
Path.GetDirectoryName(fileName) + "\";Extendet Properties ='text;HDR=yes;FMT=Delimited(,)';"))
*/
using (OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
Path.GetDirectoryName(fileName) + ";Extendet Properties ='text;HDR=yes;FMT=Delimited(,)';"))
{
using(OleDbCommand cmd = new OleDbCommand(string.Format("select *from [{0}]", new FileInfo(fileName).Name,cn)))
{
cn.Open();
using(OleDbDataAdapter adapter = new OleDbDataAdapter(cmd))
{
adapter.Fill(dt);
}
}
}
return dt;
}
Another attempt i did was using StreamReader. But the Headers are in the wrong place and i dont know how to Change this + do this for every file. the Code i tried is the following:
public static DataTable ReadCsvFilee(string path)
{
DataTable oDataTable = new DataTable();
var fileNames = Directory.GetFiles(path);
foreach (var fileName in fileNames)
{
//initialising a StreamReader type variable and will pass the file location
StreamReader oStreamReader = new StreamReader(fileName);
// CONTROLS WHETHER WE SKIP A ROW OR NOT
int RowCount = 0;
// CONTROLS WHETHER WE CREATE COLUMNS OR NOT
bool hasColumns = false;
string[] ColumnNames = null;
string[] oStreamDataValues = null;
//using while loop read the stream data till end
while (!oStreamReader.EndOfStream)
{
String oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split(';');
//Bcoz the first row contains column names, we will poluate
//the column name by
//reading the first row and RowCount-0 will be true only once
// CHANGE TO CHECK FOR COLUMNS CREATED
if (!hasColumns)
{
ColumnNames = oStreamRowData.Split(';');
//using foreach looping through all the column names
foreach (string csvcolumn in ColumnNames)
{
DataColumn oDataColumn = new DataColumn(csvcolumn.ToUpper(), typeof(string));
//setting the default value of empty.string to newly created column
oDataColumn.DefaultValue = string.Empty;
//adding the newly created column to the table
oDataTable.Columns.Add(oDataColumn);
}
// SET COLUMNS CREATED
hasColumns = true;
// SET RowCount TO 0 SO WE KNOW TO SKIP COLUMNS LINE
RowCount = 0;
}
else
{
// IF RowCount IS 0 THEN SKIP COLUMN LINE
if (RowCount++ == 0) continue;
//creates a new DataRow with the same schema as of the oDataTable
DataRow oDataRow = oDataTable.NewRow();
//using foreach looping through all the column names
for (int i = 0; i < ColumnNames.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
//adding the newly created row with data to the oDataTable
oDataTable.Rows.Add(oDataRow);
}
}
}
//close the oStreamReader object
oStreamReader.Close();
//release all the resources used by the oStreamReader object
oStreamReader.Dispose();
}
return oDataTable;
}
I am thankful for everyone who is willing to help. And Thanks for reading this far!
Sincerely yours
If I understood you right, there is a strict parsing there like this:
string OpenAndParse(string filename, bool firstFile=false)
{
var lines = File.ReadAllLines(filename);
var parsed = lines.Select(l => l.Split(';')).ToArray();
var header = $"{parsed[0][0]};{parsed[1][0]};{parsed[2][0]};{parsed[1][0]}\n";
var data = $"{parsed[0][1]};{parsed[1][1]};{parsed[2][1]};{parsed[1][2]}\n";
return firstFile
? $"{header}{data}"
: $"{data}";
}
Where it would return - if first file:
Header1;Header2;Header3;Header2
Value1;Value2;Value3;Value4
if not first file:
Value1;Value2;Value3;Value4
If I am correct, rest is about running this against a list file of files and joining the results in an output file.
EDIT: Against a directory:
void ProcessFiles(string folderName, string outputFileName)
{
bool firstFile = true;
foreach (var f in Directory.GetFiles(folderName))
{
File.AppendAllText(outputFileName, OpenAndParse(f, firstFile));
firstFile = false;
}
}
Note: I missed you want a DataTable and not an output file. Then you could simply create a list and put the results into that list making the list the datasource for your datatable (then why would you use semicolons in there? Probably all you need is to simply attach the array values to a list).
(Adding as another answer just to make it uncluttered)
void ProcessMyFiles(string folderName)
{
List<MyData> d = new List<MyData>();
var files = Directory.GetFiles(folderName);
foreach (var file in files)
{
OpenAndParse(file, d);
}
string[] headers = GetHeaders(files[0]);
DataGridView dgv = new DataGridView {Dock=DockStyle.Fill};
dgv.DataSource = d;
dgv.ColumnAdded += (sender, e) => {e.Column.HeaderText = headers[e.Column.Index];};
Form f = new Form();
f.Controls.Add(dgv);
f.Show();
}
string[] GetHeaders(string filename)
{
var lines = File.ReadAllLines(filename);
var parsed = lines.Select(l => l.Split(';')).ToArray();
return new string[] { parsed[0][0], parsed[1][0], parsed[2][0], parsed[1][0] };
}
void OpenAndParse(string filename, List<MyData> d)
{
var lines = File.ReadAllLines(filename);
var parsed = lines.Select(l => l.Split(';')).ToArray();
var data = new MyData
{
Col1 = parsed[0][1],
Col2 = parsed[1][1],
Col3 = parsed[2][1],
Col4 = parsed[1][2]
};
d.Add(data);
}
public class MyData
{
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
public string Col4 { get; set; }
}
I don't know if this is the best way to do this. But what i would have done in your case, is to rewrite the CSV's the conventionnal way while reading all the files, then create a stream containing the new CSV created.
It would look like something like this :
var csv = new StringBuilder();
csv.AppendLine("Header1;Header2;Header3;Header4");
foreach (var item in file)
{
var newLine = string.Format("{0},{1},{2},{3}", item.value1, item.value2, item.value3, item.value4);
csv.AppendLine(newLine);
}
//Create Stream
MemoryStream stream = new MemoryStream();
StreamReader reader = new StreamReader(stream);
//Fill your data table here with your values
Hope this will help.
This question already has answers here:
Reading CSV file and storing values into an array
(21 answers)
Closed 8 years ago.
I am a learner in C#. I want to read a particular value from the CSV file. I have learned the getting the csv file into a datatable through browsing. Please see the following code (Thanks to surendra jha) and my CSV file format. Say, I want to get what is the 'Volume' for 'ID' = 90.
CSV file
ID:Volume:Name
100:5600:A
95:5000:B
90:4500:C
85:4000:D
Code for getting all the values:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
namespace DVHConsolePrj
{
class Program
{
static void Main(string[] args)
{
readCsvFileData();
}
static void readCsvFileData()
{
string path = #"C:\IDVolumeName.txt";
StreamReader streamreader = new StreamReader(path);
DataTable datatable = new DataTable();
int rowcount = 0;
string[] columnname = null;
string[] streamdatavalue = null;
while (!streamreader.EndOfStream)
{
string streamrowdata = streamreader.ReadLine().Trim();
if (streamrowdata.Length > 0)
{
streamdatavalue = streamrowdata.Split(':');
if (rowcount == 0)
{
rowcount = 1;
columnname = streamdatavalue;
foreach (string csvheader in columnname)
{
DataColumn datacolumn = new DataColumn(csvheader.ToUpper(), typeof(string));
datacolumn.DefaultValue = string.Empty;
datatable.Columns.Add(datacolumn);
}
}
else
{
DataRow datarow = datatable.NewRow();
for (int i = 0; i < columnname.Length; i++)
{
datarow[columnname[i]] = streamdatavalue[i] == null ? string.Empty : streamdatavalue[i].ToString();
}
datatable.Rows.Add(datarow);
}
}
}
streamreader.Close();
streamreader.Dispose();
foreach (DataRow dr in datatable.Rows)
{
string rowvalues = string.Empty;
foreach (string csvcolumns in columnname)
{
rowvalues += csvcolumns + "=" + dr[csvcolumns].ToString() + " ";
}
Console.WriteLine(rowvalues);
}
Console.ReadLine();
}
}
}
Instead of parsing the file manually in a DataTable, then doing some Linq, use Linq directly on it, using this library.
It works pretty well and is very efficient with big files.
For instance.
1) Add nuget package in your project, and the following line to be able to use it:
using LINQtoCSV;
2) define the class that olds the data
public class IdVolumeNameRow
{
[CsvColumn(FieldIndex = 1)]
public string ID { get; set; }
[CsvColumn(FieldIndex = 2)]
public decimal Volume { get; set; }
[CsvColumn(FieldIndex = 3)]
public string Name{ get; set; }
}
3) and search for the value
var csvAttributes = new CsvFileDescription
{
SeparatorChar = ':',
FirstLineHasColumnNames = true
};
var cc = new CsvContext();
var volume = cc.Read<IdVolumeNameRow>(#"C:\IDVolumeName.txt", csvAttributes)
.Where(i => i.ID == "90")
.Select(i => i.Volume)
.FirstOrDefault();
public DataTable CSVToDataTable(string filename, string separator)
{
try
{
FileInfo file = new FileInfo(filename);
OleDbConnection con =
new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"" +
file.DirectoryName + "\";
Extended Properties='text;HDR=Yes;FMT=Delimited(" + separator + ")';")
OleDbCommand cmd = new OleDbCommand(string.Format
("SELECT * FROM [{0}]", file.Name), con);
con.Open();
DataTable tbl = new DataTable();
using (OleDbDataAdapter adp = new OleDbDataAdapter(cmd))
{
tbl = new DataTable("MyTable");
adp.Fill(tbl);
}
return tbl;
}
catch(Exception ex)
{
throw ex;
}
finally()
{
con.Close();
}
}
You can try this code, it is build on the fly, it is possible little errors to exist. Check OleDbConnection. When you return the DataTable you can search in the table using LINQ.
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("ID") == 90
select myRow;
Here you can take the row with ID=90 !
For filtering DataTable you can use DataTable.Select method like this
var filtered = dataTable.Select("ID = '90'");
filtered above is array of datarow that suitable for the condition, so for get value from first filtered row you can use something like
if(filtered.Length>0){
var Volume = filtered[0]["VOLUME"];
}
I'm using this code to parse the values and store them in List. The first row has names which are getting stored fine. But when storing values, only the second row is bring saved. I'm not sure what edit I need to make so that it parses all other rows as well.
Please see image and code below.
List<string> names = new List<string>(); // List to store Key names
List<string> values = new List<string>(); // List to store key values
using (StreamReader stream = new StreamReader(filePath))
{
names = stream.ReadLine().Split(',').ToList(); // Seperate key names and store them in a List
values = stream.ReadLine().Split(',').ToList(); // Seperate key values and store them in a list
}
See if something like this works better:
// List to store Key names
List<string> names = new List<string>();
// List to store key values
List<List<string>> values = new List<string>();
using (StreamReader stream = new StreamReader(filePath))
{
if(!stream.EndOfStream)
{
// Seperate key names and store them in a List
names = stream.ReadLine().Split(',').ToList();
}
while(!stream.EndOfStream)
{
// Seperate key values and store them in a list
values.Add(stream.ReadLine().Split(',').ToList());
}
}
This changes your values list to be a list of a list of strings so that each row will a list of string
While this probably isn't the best way to parse a .csv, if your data is consistent and the file format is strongly consistent you can probably get away with doing it like this. As soon as you try this with odd values, quoted strings, strings with commas, etc., you'll need a different approach.
i have written the code for grid view make changes it to a list.I think it will help
protected void Button1_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
string s = FileUpload1.FileName.Trim();
if (s.EndsWith(".csv"))
{
FileUpload1.PostedFile.SaveAs(Server.MapPath("~/data/" + s));
string[] readText = File.ReadAllLines(Server.MapPath("~/data/" + s));
DataSet ds = new DataSet();
DataTable dt = new DataTable();
// Array.Sort(readText);
for (int i = 0; i < readText.Length; i++)
{
if (i == 0)
{
string str = readText[0];
string[] header = str.Split(',');
dt.TableName = "sal";
foreach (string k in header)
{
dt.Columns.Add(k);
}
}
else
{
DataRow dr = dt.NewRow();
string str1 = readText[i];
if (readText[i] == ",,,,")
{
break;
}
string[] rows = str1.Split(',');
if (dt.Columns.Count == rows.Length)
{
for (int z = 0; z < rows.Length; z++)
{
if (rows[z] == "")
{
rows[z] = null;
}
dr[z] = rows[z];
}
dt.Rows.Add(dr);
}
else
{
Label1.Text = "please select valid format";
}
}
}
//Iterate through the columns of the datatable to set the data bound field dynamically.
ds.Merge(dt);
Session["tasktable"] = dt;
foreach (DataColumn col in dt.Columns)
{
BoundField bf = new BoundField();
bf.DataField = col.ToString();
bf.HeaderText = col.ColumnName;
if (col.ToString() == "Task")
{
bf.SortExpression = col.ToString();
}
GridView1.Columns.Add(bf);
}
GridView1.DataSource = ds;
GridView1.DataBind();
}
else
{
Label1.Text = "please select a only csv format";
}
}
else
{
Label1.Text = "please select a file";
}
}
I'm trying to make an app for work where I enter some data into some controls (start date and end date wage week ) and then the user picks a csv extract from our wage program. The app then merges the data from the controls and the csv file into a datatable which is then set as the datacontxct of the wpf datagrid view.
this.dgCSVData.DataContext = oDS.Tables[0].DefaultView;
So as I under stand it the datagrid is now bound (that is a question not a statement) Here is a screen shot
The datagrid is in the "shape" of the datatable in the sql database I want to append the data to. However the datatable was created in a private event handler CSV_Load_Click, code block below.
What I had hoped to do is set another button event handler up call "Upload Data" and pass the datatable (oDS.Tables[0].DefaultView) to the DAL layer to be read and appended to sql database table, the problem is how do I make the datatable available, should I have created a class to match my data row and then created a public list of the rows?
private void CSV_Load_Click(object sender, RoutedEventArgs e)
{
//Turn on upload button
btUpload.IsEnabled = true;
//To load and display CSV data
//string filename = txFilePath.Text;
string delimStr = ",,";
char[] delimiter = delimStr.ToCharArray();
string strFilePath = txFilePath.Text;
DataSet oDS = new DataSet();
string strFields = null;
DataTable oTable = new DataTable();
DataRow oRows = null;
Int32 intCounter = 0;
oDS.Tables.Add("Property");
StreamReader oSR = new StreamReader(strFilePath);
//Go to the top of the file
oSR.BaseStream.Seek(0, SeekOrigin.Begin);
string File = fileTest;
//System.Windows.MessageBox.Show(File.ToString());
//Add in the Header Columns check if headers in first row
if (rbYes.IsChecked==true)
// action for headers in row 1
{
foreach (string strFields_loopVariable in oSR.ReadLine().Split(delimiter))
{
strFields = strFields_loopVariable;
oDS.Tables[0].Columns.Add(strFields);
}
}
else
{
if (File==#"CHHOURS.CSV")
{
string TitleHeaders = "Wage_Year,Wage_Start_Date,Wage_End_Date,Tax Week,Wk_No,Clock,Surname,Initial,Dept,Dept_Hours,Other_Hours,Total_Hours,OT_Hours,";
foreach (string strFields_loopVariable in TitleHeaders.Split(delimiter))
{
strFields = strFields_loopVariable;
oDS.Tables[0].Columns.Add(strFields);
}
}
else
{
Int32 i = 0;
foreach (string strFields_loopVariable in oSR.ReadLine().Split(delimiter))
{
string ColumLetter = "abcdefghijklmnopqrstuvwxyz";
strFields = ColumLetter[i].ToString();
oDS.Tables[0].Columns.Add(strFields);
i += 1;
}
}
}
//String request = oSR.ReadToEnd();
//Now add in the Rows
oTable = oDS.Tables[0];
while ((oSR.Peek() > -1))
{
oRows = oTable.NewRow();
if (File == #"CHHOURS.CSV")
{
oRows[intCounter] = cbWageYear.Text;
intCounter = intCounter + 1;
oRows[intCounter] = dpStartDate.SelectedDate;
intCounter = intCounter + 1;
oRows[intCounter] = dpEndDate.SelectedDate;
intCounter = intCounter + 1;
oRows[intCounter] = cBTaxWeek.SelectedIndex;
intCounter = intCounter + 1;
}
foreach (string strFields_loopVariable in oSR.ReadLine().Split(delimiter))
{
strFields = Convert.ToString(strFields_loopVariable);
if (intCounter < 20)
{
oRows[intCounter] = strFields;
intCounter = intCounter + 1;
}
else
{
}
}
intCounter = 0;
oTable.Rows.Add(oRows);
}
this.dgCSVData.DataContext = oDS.Tables[0].DefaultView;
}
Ok so I woke up this morning with an idea and It worked .wow!
All I did was declare my dataset as public before the constructor of my class. Now there might be a "better" way but that worked for me. Ii have been able to call my update method from my DAL and create a datareader, so now just the update to sql to do, then bug fixing.
I am almost happy :)
here is the code
public partial class MainWindow : Window
{
public List<TaxWeek> LTaxWeeks { get; set; }
public TaxWeek SelectedTaxWeek { get; set; }
**public DataSet oDS = new DataSet();**
public MainWindow()
{
InitializeComponent();
}