Ok, so I have a class, customer, that I use to process data, and then add to a list box, like below:
//Submit data from current form
customer aCustomer = new customer(comboBox1.Text, textBox1.Text, ChannelSelecBox.Text,
PurchaserTextBox.Text, NameTextBox.Text, emailTextBox.Text, AddressTextBox.Text, StateBox.Text,
PayMethodDropDown.Text, Prod1Num.Value.ToString(), Prod2Num.Value.ToString(),
Prod3Num.Value.ToString(), Prod4Num.Value.ToString(), Prod5Num.Value.ToString(),
Prod6Num.Value.ToString(), SubTData.Text, DiscountTextBox.Text, TaxData.Text, CommentTextBox.Text,
ShipData.Text, TotalData.Text);
// Add aCustomer to ListBox
Orders.Items.Add(aCustomer);
I have a string override so that the listbox just displays the purchaser and the date.
Now I want to take all the orders entered into the list box and put, most of, this data into an excel spreadsheet, each into it's own column. How could I do this?
If you need more information or to see more of my code, let me know.
try the following;
object oOpt = System.Reflection.Missing.Value; //for optional arguments
Excel.Application oXL = new Excel.Application();
Excel.Workbooks oWBs = oXL.Workbooks;
Excel.Workbook oWB = oWBs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel.Worksheet oSheet = (Excel.Worksheet)oWB.ActiveSheet;
//outputRows is a List<List<object>>
int numberOfRows = outputRows.Count;
int numberOfColumns = outputRows.Max(list => list.Count);
Excel.Range oRng =
oSheet.get_Range("A1", oOpt)
.get_Resize(numberOfRows, numberOfColumns);
object[,] outputArray = new object[numberOfRows, numberOfColumns];
for (int row = 0; row < numberOfRows; row++)
{
for (int col = 0; col < outputRows[row].Count; col++)
{
outputArray[row, col] = outputRows[row][col];
}
}
oRng.set_Value(oOpt, outputArray);
oXL.Visible = true;
more details can be found at http://csharp.net-informations.com/excel/csharp-create-excel.htm
Use CSV as file format, not XLS. Excel is a pain. Especially when reading from XLS. Some incorrect cell formatting and you sometimes get the value, but sometimes not. Even in same file. Personal experience.
Related
I am unable to export data from multiple rows in DTG to specific columns in excel. I have tried multiple methods from forums. So far, the results are excel opened but no data are exported (empty cells) or only the last row of DTG are copied to the specific columns in excel.
I want this excel sheet to compile the DTG data. Hence, example user open form 1st time, enter DTG data, saves to excel and closes form. User then open form 2nd time and enter another DTG data, the 2nd DTG data will go into the same excel columns but on the next empty row (underneath the row of the 1st DTG data).
Most codes that I've tried comes from this link [Programmatically getting the last filled excel row using C# ]. I did not put the column part as I only want last row. Do note that the skeleton of all the codes are the same but the way lastUsedRow was initialized are different.
Codes below gives empty cells
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
try
{
oXL = new Microsoft.Office.Interop.Excel.Application();
oWB = oXL.Workbooks.Open("C:\\Users\\User\\Test.xlsx");
oSheet = oXL.Worksheets["Vehicles"];
Excel.Range last = oSheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range range = sheet.get_Range("A1", last);
int lastUsedRow = last.Row;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
for (int j = 1; j < dataGridView1.Columns.Count; j++)
{
oSheet.Cells[lastUsedRow, j+1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
}
OR
int lasUsedRow = oSheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing).Row;
Codes below shows only last row of DTG
int lastUsedRow = oSheet.Cells.Find("*",System.Reflection.Missing.Value,
System.Reflection.Missing.Value, System.Reflection.Missing.Value, Excel.XlSearchOrder.xlByRows,Excel.XlSearchDirection.xlPrevious, false,System.Reflection.Missing.Value,System.Reflection.Missing.Value).Row;
OR
int lastUsedRow = oSheet.Range["B" + oSheet.Rows.Count].End[Excel.XlDirection.xlUp].Row+1;
Hope to get some help. Thank you so much!
As per Yoshi's comment, below is the updated code where it allows multiple datagridview rows to be added and compiled into excel.
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
try
{
//Start Excel and get Application object.
oXL = new Microsoft.Office.Interop.Excel.Application();
//Get a new workbook.
oWB = oXL.Workbooks.Open("C:\\Users\\User\\Test.xlsx");
//Specify different sheet names
oSheet = oXL.Worksheets["Vehicles"];
//Define last row
int _lastRow = oSheet.Range["B" + oSheet.Rows.Count].End[Excel.XlDirection.xlUp].Row+1;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
for (int j = 1; j < dataGridView1.Columns.Count; j++)
{
oSheet.Cells[_lastRow, j+1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
_lastRow++;
}
//Make sure Excel open and give the user control of Microsoft Excel's lifetime.
oXL.Visible = true;
oXL.UserControl = true;
//Autosave excel file
oWB.Save();
Marshal.ReleaseComObject(oXL);
}
catch (Exception theException)
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat(errorMessage, theException.Message);
errorMessage = String.Concat(errorMessage, " Line: ");
errorMessage = String.Concat(errorMessage, theException.Source);
MessageBox.Show(errorMessage, "Error");
}
}
I am desperately trying to add multiple items from an excel sheet into a listview using c#. I have looked all over the Internet for a working solution but still no result.
I would like to ask anybody who knows about c#'s listview for an helping hand...
Thanks in advance
code so far:-
public void InitializeListView(string path) {
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook sheet = excel.Workbooks.Open(path);
Microsoft.Office.Interop.Excel.Worksheet wx = excel.ActiveSheet as Microsoft.Office.Interop.Excel.Worksheet;
int count = 0;
int row = 0;
int col = 0;
Excel.Range userrange = wx.UsedRange;
count = userrange.Rows.Count;
statusBar1.Panels[1].Text = "Amount: " + count;
for (row = 1; row <= count; row++) {
for (col = 1; col <= 4; col++) {
listView1.Items.Add(wx.Cells[row, col].Value2);
listView1.Items.Add(wx.Cells[row, col].Value2);
listView1.Items.Add(wx.Cells[row, col].Value2);
listView1.Items.Add(wx.Cells[row, col].Value2);
}
}
sheet.Close(true, Type.Missing, Type.Missing);
excel.Quit();
}//------------------ end of InitializeListView -------------------------
This might be help you please see https://www.codeproject.com/Questions/460391/Retrieve-datas-from-Excel-Sheet-to-Listview
This is a simple method. Please look if it helps you.
1. Convert the Excel file in to .csv and Store it in the a Path
2. Take the data from .csv file to list.
3. Delete the .csv file once all data is loaded in List<>.
To Read from .csv
string filepath = "D:\\sample.csv";
var lineCount = File.ReadAllLines(#"D:\\sample.csv").Length;
int TotalLines = Int32.Parse(lineCount.ToString());
StreamReader sr = new StreamReader(filepath);
string line;
List<string> lstSample = new List<string>();
while ((line = sr.ReadLine()) != null)
{
lstSample = line.Split(',').ToList();
}
I have an Excel file (xls) which contains a series of drop down lists in column F on the first sheet. Each drop down list contains more than 7 options, which are all strings. Each row has a different value selected. Below is how the drop down lists were originally created using Microsoft.Office.Interop:
Application xlApp = new ApplicationClass();
Workbook xlWorkBook = null;
Worksheet xlWorkSheet = null;
object misValue = System.Reflection.Missing.Value;
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
Microsoft.Office.Interop.Excel.Range dropDownRange = xlWorkSheet.get_Range("F" + index, misValue);
Microsoft.Office.Interop.Excel.DropDowns dropDowns = (Microsoft.Office.Interop.Excel.DropDowns)xlWorkSheet.DropDowns(misValue);
Microsoft.Office.Interop.Excel.DropDown dropDown = dropDowns.Add((double)dropDownRange.Left, (double)dropDownRange.Top, (double)dropDownRange.Width, (double)dropDownRange.Height, true);
string[] currency = Config.listofCurrency();
for (int i = 0; i < currency.Length; i++)
{
dropDown.AddItem(currency[i], i + 1);
if (currency[i].ToLower() == defaultCurrency.ToLower())
{
dropDown.set_Selected(i + 1, misValue);
}
}
xlWorkSheet.get_Range("F" + index, misValue).set_Value(Microsoft.Office.Interop.Excel.XlRangeValueDataType.xlRangeValueDefault, dropDown);
Now I am trying to read the file using NPOI to get the values of the cells in column F from the same file. Here is the code I am using:
using (FileStream fileStream = new FileStream("excel.xls", FileMode.Open, FileAccess.Read))
{
HSSFWorkbook hSSFWorkbook = new HSSFWorkbook(fileStream);
ISheet isheet = hSSFWorkbook.GetSheetAt(0);
IRow currentRow;
for (int rowNumber = 1; rowNumber <= isheet.LastRowNum; rowNumber++)
{
currentRow = isheet.GetRow(rowNumber);
ICell cell = currentRow.GetCell(5);
Console.WriteLine(currentRow.GetCell(5).ToString());
}
}
But instead of string values, I am finding that the cell types are all numeric, and are all set to the value 7 which doesn't relate to the selected values in the dropdowns.
How can I get the correct values of the cells in NPOI?
Tested using EPPLus and ClosedXML, both give me 7s.
Im using Visual Studio to create an automated test that creates two excel sheets. As a final check, I need to compare the content of these two excel sheets and ensure that they are equal. Is there any way to do this with assertions?
Something like Assert.AreEqual(file1, file2);?
Any help or guidance would be appreciated!
Thanks to Mangist for guidance on this. Ive written the following to compare two excel files:
public bool compareFiles(string filePath1, string filePath2)
{
bool result = false;
Excel.Application excel = new Excel.Application();
//Open files to compare
Excel.Workbook workbook1 = excel.Workbooks.Open(filePath1);
Excel.Workbook workbook2 = excel.Workbooks.Open(filePath2);
//Open sheets to grab values from
Excel.Worksheet worksheet1 = (Excel.Worksheet)workbook1.Sheets[1];
Excel.Worksheet worksheet2 = (Excel.Worksheet)workbook2.Sheets[1];
//Get the used range of cells
Excel.Range range = worksheet2.UsedRange;
int maxColumns = range.Columns.Count;
int maxRows = range.Rows.Count;
//Check that each cell matches
for (int i = 1; i <= maxColumns; i++)
{
for (int j = 1; j <= maxRows; j++)
{
if (worksheet1.Cells[j, i].Value == worksheet2.Cells[j, i].Value)
{
result = true;
}
else
result = false;
}
}
//Close the workbooks
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.ReleaseComObject(range);
Marshal.ReleaseComObject(worksheet1);
Marshal.ReleaseComObject(worksheet2);
workbook1.Close();
workbook2.Close();
excel.Quit();
Marshal.ReleaseComObject(excel);
//Tell us if it is true or false
return result;
}
And using an assertion to check result:
Assert.IsTrue(compareFiles(testFile, compareFile), "Output files do not match.");
Can you convert the expected/actual Excel sheets to a text format, such as CSV?
If so, you could use Approval Tests instead. This allows you to have a text file as your "expected" test result. When tests fail it can show you the actual result of the test, diff'd against the expected result.
Screenshot taken from this review of Approval Tests.
One Option will be using Open source library called as EPPlus. You can download and refer it in you automated test application. EPPlus gives you multiple ways to read an excel file and compare. One such option is C# Datatable. Here is a sample code..
public static DataTable GetDataTableFromExcel(string path, bool hasHeader = true)
{
using (var pck = new OfficeOpenXml.ExcelPackage())
{
using (var stream = File.OpenRead(path))
{
pck.Load(stream);
}
var ws = pck.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
{
tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
}
var startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
return tbl;
}
}
For both the Excel files , same process can be adopted, and it will give you the desired results.
So I have a list of data that I am trying to export to excel. I just want to list it going down column 1 but it refuses. I was originally going to use a foreach loop but i was worried that would slow down my program and i wouldn't be able to use the for loop idea i had. Does anyone have any good ideas to just import this. I feel like it shouldn't be as hard as i am making it. This is what i have done so far. Thanks in advance.
if (dialog == DialogResult.Yes)
{
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Workbook wb = excel.Workbooks.Add(XlSheetType.xlWorksheet);
Worksheet ws = (Worksheet)excel.ActiveSheet;
ws.Cells[1, 1] = "Folder Names";
for (int row = 0; row <= count; row++)
{
ws.Cells [1, row+2] = Namelist;
}
excel.Visible = true;
}
I want to go sequentially down the list as well. (the code above wont export Namelist, rest works though)
Namelist = list
int count (it is a counter i started earlier in the program to determine the number of lines of Namelist)
If Namelist is List<string>, the easiest way is to copy it to the Clipboard:
var text = "Folder Names\n" + string.Join("\n", Namelist); // or "\r\n"
System.Windows.Forms.Clipboard.SetText(text);
var xl = new Microsoft.Office.Interop.Excel.Application();
var wb = xl.Workbooks.Add();
var ws = xl.ActiveSheet as Worksheet;
ws.Range("A1").PasteSpecial();
xl.Visible = true;
or even easier because Excel is associated with .csv files by default:
var fileName = #"list.csv"; // or change to .xls and get warning message box
System.IO.File.WriteAllText(fileName, "Folder Names\n" + string.Join("\n", Namelist));
System.Diagnostics.Process.Start(fileName);
Update
CSV stands for Comma Separated Values, so if you want the list in a different column you have to add commas before the values. For example in columns 2 and 4:
,Folder Names,,Folder Size
,name1,,256
,name2,,"1,024"
If you have 2 lists with the same size, you can zip them together:
string[] names = {"name1", "name2"};
int[] sizes = {256, 1024};
var lines = names.Zip(sizes, (name, size) => name + "," + size); // {"name1,256", "name2,1024"}
var csv = "Names,Sizes\n" + string.Join("\n", lines);
The for loop won't slow down your program, but accessing the cells individually will. Each call to Cells is a COM-interop call, which is relatively expensive. It's much faster to put your data in an array, define a Range that represents the entire range of output, and set the Value there:
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
var wbs = excel.Workbooks;
Workbook wb = wbs.Add(XlSheetType.xlWorksheet);
Worksheet ws = (Worksheet)excel.ActiveSheet;
List<object> data = new List<object>
data.Add("Folder Names");
for (int row = 0; row <= count; row++)
{
data.Add(Namelist);
}
Excel.Range rng = (Excel.Range)ws.Range[ws.Cells[1, 1], ws.Cells[1,count + 2]];
rng.Value = data.ToArray();
excel.Visible = true;
Assuming Namelist is a string[] or List<string> what you're missing is the extraction of each item from the Namelist collection before setting the value of each cell:
ws.Cells[1, 1] = #"Folder names";
for(int row = 2; row <= count; row ++)
{
var name = Namelist[row-2];
ws.Cells[1, row] = name;
}
When you use the Cells property the first argument is the row, the second is the column. You have it reversed.
Also, if you haven't gone too far down the path of learning Excel interop, I would switch to EPPlus. It's 100x times easier to work with, doesn't involve messing with COM objects, and doesn't even require Excel. It's just better.
Super easy way to export your list to excel using c#
How to install ClosedXML with NuGet Packager Manager Console:
PM> Get-Project [ProjectName] | Install-Package ClosedXML
using (var conn = new DB.Entities())
{
var stories = (from a in conn.Subscribers
orderby a.DT descending
select a).Take(100).ToList();
var ShowHeader = true;
PropertyInfo[] properties = stories.First().GetType().GetProperties();
List<string> headerNames = properties.Select(prop => prop.Name).ToList();
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add("Subscribers");
if (ShowHeader)
{
for (int i = 0; i < headerNames.Count; i++)
ws.Cell(1, i + 1).Value = headerNames[i];
ws.Cell(2, 1).InsertData(stories);
}
else
{
ws.Cell(1, 1).InsertData(stories);
}
wb.SaveAs(#"C:\Testing\yourExcel.xlsx");
}