I need to write a list of objects to excel sheet as a table, in which each column represents object attributes or values. To the below method, Im passing column names in a separate List and data objects in a List, I managed to get the data displayed like below, but still I could not get the columns to display properly.
I referred the below documentation, but I could not find a way to get the titles display properly.
https://github.com/closedxml/closedxml/wiki/Inserting-Tables
Code
public string CreateExcelFile<T>(IEnumerable<T> list, string sheetName, string headerTitle, List<string> titles, string fileName, string savedPath)
{
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add(sheetName);
ws.Cell(1, 1).Value = headerTitle; // sets excel sheet header
var rangeTitle = ws.Range(3, 1, 3, titles.Count); // range for row 3, column 1 to row 3, column titles.Count
rangeTitle.AddToNamed("Titles");
// Need to add columns names with in rangeTitle
//rangeTitle.InsertData(titles);
// write data from row 4 onwards
if (list != null && list.Any())
{
ws.Cell(4, 1).InsertData(list);
}
else
{
ws.Cell(4, 1).Value = "No data to show";
}
// styles
var titlesStyle = wb.Style;
titlesStyle.Font.Bold = true;
titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
titlesStyle.Fill.BackgroundColor = XLColor.Amber;
// style titles row
wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle;
ws.Columns().AdjustToContents();
var filePath = savedPath + string.Format("{0}.xlsx", fileName);
wb.SaveAs(filePath);
return filePath;
}
Output excel
Output Im trying to get - I need to get values stored in titles in the Yellow highlighted row.
Can anyone help?
You could use InsertTable. The data is inserted as an Excel Table:
ws.Cell(1, 1).InsertTable(list.AsEnumerable());
I managed to get the columns to display by doing below.
// Need to add columns names with in rangeTitle
for (int i = 0; i < titles.Count; i++)
{
var columnNumber = i + 1;
ws.Cell(3, columnNumber).Value = titles[i];
}
This works for now. But, I wonder is there a better way to doing things (without manually assigning column names like above).
ws.Cell(3, 1).Value = new [] { titles };
If you set Value to an array, ClosedXML will write each object in the array to its own row, with one property of the object per column. (See https://github.com/ClosedXML/ClosedXML/wiki/Copying-IEnumerable-Collections)
In this case, the array we're passing in has only one object – an array of titles. That inner array gets written to the target row, and each item in the inner array gets written to a column in that row.
Related
i have a tables like this
and i added checkboxs elements to form like this
i want to add the checkbox element text to datagridview then read the checked columns from excel file
if Date, Time, Price are checked datagridview will be like this
then get full Date column from excel file and add it to Date column in datagrid
my code to add checked boxes text as a columns in datagridview
DataTable dt = new DataTable();
foreach (Control checkbox in pnl.Controls)
if (checkbox.GetType() == typeof(CheckBox) && ((CheckBox) checkbox).Checked)
{
string txt = ((CheckBox)checkbox).Text;
dt.Columns.Add(new DataColumn(txt, typeof(object)));
}
datagrid.DataSource = dt;
There are a few steps which are needed before being able to grab data from an Excel file. So without your code, I don't know how much of this you have done. But here is the full explanation.
First
You have to add a reference to the Microsoft.Office.Interop.Excel dll (this assumes you aren't using epplus or another Nuget package). This link describes how to do this: How to reference Microsoft.Office.Interop.Excel dll?
Second
Include this library in whichever source file it is needed, and initialize an excel application (you'll also want InteropServices included):
using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
// Global excel app object to be used anywhere
public Application ExcelApp;
// Intitializes an excel application by looking for an active one,
// and creating a new one if none are active
public void InitExcelApp()
{
try
{
ExcelApp = (Application)Marshal.GetActiveObject("Excel.Application")
}
catch(COMException ex)
{
ExcelApp = new Application
{
Visible = true
};
}
}
Third
You must initialize a workbook object. Here is how I do it, but my solution assumes you know the path to the desired Excel workbook:
Workbook myWorkbook = null;
// Checks open workbooks first
// Note that the path must be windows style. Ex: "C:\\Desktop\\myWorkbook.xlsx"
foreach (Workbook openWorkbook in ExcelApp.Workbooks)
{
if (openWorkbook.FullName == "<path to workbook>")
{
myWorkbook = openWorkbook;
}
}
// If no open workbooks were found at the known path, try opening one
if(myWorkbook is null)
{
myWorkbook = Excelapp.Workbooks.Open("<path to workbook>", Editable: true);
}
Fourth
Get the data you want. There are several ways to do this, and mine might not be the most efficient, but it works. In the code below I have included parameter names to hopefully make it more understandable.
// Gets the names of the checked items from the DataTable with columns you already added
// You could get these names from your checkboxes' names if you preferred
List<string> checkItems = new List<string>();
foreach (System.Data.DataColumn column in dt.Columns)
{
checkItems.Add(column.ColumnName);
}
// This dictionary holds info helpful for getting the correct data from excel:
// Key: a string containing the name of the column header, i.e. Date, Time, Price, etc.
// Value: an integer containing the number of that column in excel
Dictionary<string, int> excelColumnsInfo = new Dictionary<string, int>();
for (int columnNum = 1; columnNum <= myWorkbook.UsedRange.Columns.Count; columnNum++)
{
string columnHeader = myWorkbook.Cells[RowIndex: 1, ColumnIndex: columnNum].Value2.ToString();
if (checkedItems.Contains(columnHeader))
{
excelColumnsInfo.add(columnHeader, columnNum);
}
}
// Populates the data table with the data you need
// Start at row 2 to ignore the excel sheet's column headers
for (int rowNum = 2; rowNum <= myWorkbook.UsedRange.Rows.Count; rowNum++)
{
System.data.dataRow newRow = dt.NewRow();
foreach (KeyValuePair<string, int> columnInfo in excelColumnsInfo)
{
newRow[columnName: columnInfo.Key] = myWorkbook.Cells[RowIndex: rowNum, ColumnIndex: columnInfo.Value].Value2.ToString();
}
dt.Rows.Add(newRow);
}
Is there any way to remove "columns" from an ArrayList?
I got this site up and running before attempting populating my DropDownLists from txt files so I hard-typed each value in. Now I've made an ArrayList from each DropDownList so I can display those lists in DataGridView on the site. The only issue is that "Enabled" and "Selected" show up as columns and I cannot seem to remove the column in the ArrayList, or specify which columns to bring in when creating the ArrayList, or GridView using GridView.Columns.Remove(); because the integers 0 or 1 or 2 don't seem to correspond with anything and the site doesn't run and I can't specify a string as the column title for what to remove.
The DataGrids show up with columns as |Enabled|Selected|Text|Value|
Here's the code for this piece as it stands (You can see what I've tried out and that didn't work that I've commented away):
// Create ListArrays from DropDownLists
ArrayList BuildingList = new ArrayList(Building.Items);
ArrayList DepartmentList = new ArrayList(Department.Items);
//Building.Items.Remove("Enabled");
//Building.Items.Remove("Selected");
// Populate Building GridView
BuildingGrid.DataSource = BuildingList;
BuildingGrid.DataBind();
//BuildingGrid.Columns.Remove;
//BuildingGrid.Columns[0].Visible = false;
// Populate Department GridView
DepartmentGrid.DataSource = DepartmentList;
DepartmentGrid.DataBind();
//DepartmentGrid.Columns[0].Visible = false;
//DepartmentGrid.Columns[1].Visible = false;
I would just go ahead and create a simple 2d array in a txt file with fields for "Value" and "Text" so the DropDownList will pull it in properly, but I can't figure that out either without being terribly inefficient and confusing.
Any help would be appreciated. Thanks.
So, here's the solution I ended up at. I finally figured out how to extract everything from a txt file, and place it into the grid the way I wanted to.
// Populate Department GridView
// get all lines of csv file
string[] BuildingString = File.ReadAllLines(Server.MapPath("Content/BuildingsCSV.csv"));
string[] DepartmentString = File.ReadAllLines(Server.MapPath("Content/DepartmentsCSV.csv"));
// create new datatable
DataTable BuildingTable = new DataTable();
DataTable DepartmentTable = new DataTable();
// Building Table
// get the column header means first line
string[] tempbuild = BuildingString[0].Split(',');
// creates columns of gridview as per the header name
foreach (string t in tempbuild)
{
BuildingTable.Columns.Add(t, typeof(string));
}
// now retrive the record from second line and add it to datatable
for (int i = 1; i < BuildingString.Length; i++)
{
string[] t = BuildingString[i].Split(',');
BuildingTable.Rows.Add(t);
}
// Department Table
// get the column header means first line
string[] tempdept = DepartmentString[0].Split(',');
// creates columns of gridview as per the header name
foreach (string t in tempdept)
{
DepartmentTable.Columns.Add(t, typeof(string));
}
// now retrive the record from second line and add it to datatable
for (int i = 1; i < DepartmentString.Length; i++)
{
string[] t = DepartmentString[i].Split(',');
DepartmentTable.Rows.Add(t);
}
// assign gridview datasource property by datatable
BuildingGrid.DataSource = BuildingTable;
BuildingGrid.DataBind();
BuildingGrid.Rows[0].Visible = false;
DepartmentGrid.DataSource = DepartmentTable;
DepartmentGrid.DataBind();
DepartmentGrid.Rows[0].Visible = false;
foreach (DataRow drb in BuildingTable.Rows)
{
BuildingDrop.Items.Add(new ListItem(drb[0].ToString(), drb[1].ToString()));
}
foreach (DataRow drd in DepartmentTable.Rows)
{
DepartmentDrop.Items.Add(new ListItem(drd[0].ToString(), drd[1].ToString()));
}
I want to select a range from the first to the last cell filled in the row or column. In VBA the code stays as below using xlDown or xlToRight.
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
How could I do it the same way in C # using Epplus?
I will start from cell B139 and I must go to the last row and column
An important thing to know about the Cells object in an Worksheet in EPPlus is that it contains only references to cell that have data added to it. So with a little bit of LINQ you can get the address of every "Row" like this:
var lastRowCell1 = worksheet.Cells.Last(c => c.Start.Row == 1);
var lastRowCell2 = worksheet.Cells.Last(c => c.Start.Row == 2);
var lastColCell1 = worksheet.Cells.Last(c => c.Start.Column == 1);
var lastColCell2 = worksheet.Cells.Last(c => c.Start.Column == 2);
To get the last Cell's index you can use worksheet.Dimension:
int numCol = worksheet.Dimension.Rows;
int numCol = worksheet.Dimension.Columns;
If you want the last address of Column or Row you can use this:
String lastAddress = worksheet.Dimension.Address.Last().ToString();
I have a DataGridView in winforms, that contains a combobox column. The gridview is filled programmatically, and it is empty at start. "list" is a list containing custom objects. Value1/2/3 are unique to each row.
int[] array = new[] {value1,value2,value3}
for (int i = 0; i < list.Count; i++)
{
DataRow newrow = MyDataTable.NewRow();
newrow["idColumn"] = list[i].Customer_id;
newrow["dateoforderColumn"] = list[i].Customer_date;
newrow["commColumn"] = list[i].Customer_comment;
// This is what I want, and can't get to work.
newrow["comboColumn"] = array;
// I have also tried (newrow["comboColumn"] as DataGridViewComboColumn).DataSource
// but it didn't work either.
MyDataTable.Rows.Add(newrow);
}
How can I populate a freshly created combobox cell? Also, I need to do it within the for loop, because I need the index to get the data.
From the look of your code you just have one array of values that you need to set. In this case you only need to set it once for the column, not for every row, i usually do this in the constructor or before populating rows.
//Clear any junk items that may have been there from the designer or previous view
((DataGridViewComboBoxColumn)MyDataTable.Columns["comboColumn"]).Items.Clear();
//Add you new values
((DataGridViewComboBoxColumn)MyDataTable.Columns["comboColumn"]).Items.AddRange(array);
Then to set the value of the new row's cell
//Set value to be selected in new row
newrow["comboColumn"] = list[i].Customer_value;
I want to do the following but using GridView of DevExpress , how Can I do that please ?
List<RCDATA_INDEX> somethings = new List<RCDATA_INDEX>();
foreach (DataGridViewRow row in (IEnumerable)this.dataGridView1.Rows)
{
AZ.RCDATA_INDEX items = new AZ.RCDATA_INDEX
{
datasize = Convert.ToUInt32(row.Cells[5].Value.ToString())
};
item.filenum = Convert.ToUInt32(row.Cells[2].Value.ToString()[7].ToString());
item.hash = row.Cells[1].Value.ToString();
item.realname = row.Cells[3].Value.ToString();
item.offset = Convert.ToUInt32(row.Cells[4].Value.ToString());
item.new_value = row.Cells[6].Value.ToString();
somethings.Add(items);
}
You can traverse through all the data rows within a GridView one-by-one, using the following approach:
// Obtain the number of data rows.
int dataRowCount = gridView.DataRowCount;
// Traverse data rows
for (int i = 0; i < dataRowCount; i++) {
object cellValue = gridView.GetRowCellValue(i, "... specify field name here ...");
// do something with cell Value
}
Please refer the Traversing Rows and Obtaining and Setting Cell Values help-articles to learn more;
I would prefer using BindingSource and bind it into Gridview. After that if you want to making manipulation of your data. You just need to call like this :
List<RCDATA_INDEX> somethings = new List<RCDATA_INDEX>();
var Result = RCDataBS.Cast<RCDATA_INDEX>();
somethings.AddRange(Result);
It would be much easier using this code and you don't need to spend your resource to convert all the data into your model.