C# ReoGrid performance issue when binding datatable with formula - c#

I have populated my data table with random values and formula like =SUM(A1:A2)
when there is 150 columns and 4000 rows in datatable then ReoGrid taking approx 20 minute to be populated.
when i am populating ReoGrid without formula then it takes few second to populate ReoGrid but the moment many SUM formulas are being assigned to cell dynamically then ReoGrid take long time to populated.
Here i am sharing my code. so my request please guys see my code logic and tell me is there any flaw when assigning formula to many cell of ReoGrid.
please tell me how could i simplify the logic to populate grid with formula. Is there way to increase the performance of my code with formula as a result ReoGrid can be populated with in few sec or few minute.
Looking for suggestion and guide line. ReoGrid is free component for winform application https://reogrid.net/.
Here is my code
private void btnBindTable_Click(object sender, EventArgs e)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
string strSum = "", strColName, strImmediateOneUp = "", strImmediateTwoUp = "";
int startsum = 0;
int currow = 0;
bool firstTimeSum = true;
int NumRows = 4000;
int NumColumns = 150;
var sheet = reoGrd.CurrentWorksheet;
sheet.Resize(NumRows, NumColumns); // resize
DataTable dt = new DataTable();
for (int col = 0; col < NumColumns; col++)
{
strColName = GenerateColumnText(col);
DataColumn datacol = new DataColumn(strColName, typeof(string));
dt.Columns.Add(datacol);
}
for (int row = 0; row < NumRows; row++)
{
dt.Rows.Add();
for (int col = 0; col < NumColumns; col++)
{
if (row < 2)
{
dt.Rows[row][col] = new Random().Next(1, NumRows).ToString("D2");
}
else
{
if (firstTimeSum)
{
if (row - currow == 2)
{
currow = row;
startsum = 0;
firstTimeSum = false;
}
else
{
startsum = 1;
}
}
else
{
if (row - currow == 3)
{
currow = row;
startsum = 0;
}
}
if (startsum == 0)
{
strColName = GenerateColumnText(col);
strImmediateOneUp = strColName + ((row + 1) - 1).ToString();
strImmediateTwoUp = strColName + ((row + 1) - 2).ToString();
dt.Rows[row][col] = strSum;
string cellname = GenerateColumnText(col) + (row + 1).ToString();
var cell = sheet.Cells[cellname];
cell.Style.BackColor = Color.LightGoldenrodYellow;
}
else
{
dt.Rows[row][col] = new Random().Next(1, NumRows).ToString("D2");
}
}
}
startsum = 1;
}
sheet["A1"] = dt;
stopwatch.Stop();
TimeSpan timeSpan = stopwatch.Elapsed;
MessageBox.Show(string.Format("Time elapsed: {0}h {1}m {2}s {3}ms", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, timeSpan.Milliseconds));
}

Related

C# EPPlus not evaluating formula SUM(A3:B3)

I have just started working with EPPlus. i have data table which has some numeric data and formula. when i load data table by EPPlus and save to excel then formula not evaluated i found when i open the same excel file. formula lies in excel cell as string like SUM(A3:B3)
To evaluate formulate i have tried many options of EPPLUS and those are listed here
pack.Workbook.Worksheets["Test"].Calculate();
pack.Workbook.Worksheets["Test"].Cells["A3"].Calculate();
pack.Workbook.Worksheets["Test"].Cells["B3"].Calculate();
ws.Calculate();
Here i am referring my full sample code where formula not working. please have a look and tell me what i need to add in my code to evaluate formula.
private void button1_Click(object sender, EventArgs e)
{
DataTable dt = GetDataTable();
string path = #"d:\EPPLUS_DT_Excel.xlsx";
Stream stream = File.Create(path);
using (ExcelPackage pack = new ExcelPackage())
{
ExcelWorksheet ws = pack.Workbook.Worksheets.Add("Test");
ws.Cells["A1"].LoadFromDataTable(dt, false);
//pack.Workbook.Worksheets["Test"].Calculate();
//pack.Workbook.Worksheets["Test"].Cells["A3"].Calculate();
//pack.Workbook.Worksheets["Test"].Cells["B3"].Calculate();
ws.Calculate();
pack.SaveAs(stream);
stream.Close();
MessageBox.Show("Done");
}
}
public DataTable GetDataTable()
{
string strSum = "", strColName, strImmediateOneUp = "", strImmediateTwoUp = "";
int startsum = 0;
int currow = 0;
bool firstTimeSum = true;
int NumRows = 3;
int NumColumns = 2;
DataTable dt = new DataTable();
for (int col = 0; col < NumColumns; col++)
{
strColName = GenerateColumnText(col);
DataColumn datacol = new DataColumn(strColName, typeof(object));
dt.Columns.Add(datacol);
}
for (int row = 0; row < NumRows; row++)
{
dt.Rows.Add();
for (int col = 0; col < NumColumns; col++)
{
if (row < 2)
{
dt.Rows[row][col] = Convert.ToInt32(new Random().Next(1, NumRows));
}
else
{
if (firstTimeSum)
{
if (row - currow == 2)
{
currow = row;
startsum = 0;
firstTimeSum = false;
}
else
{
startsum = 1;
}
}
else
{
if (row - currow == 3)
{
currow = row;
startsum = 0;
}
}
if (startsum == 0)
{
strColName = GenerateColumnText(col);
strImmediateOneUp = strColName + ((row + 1) - 1).ToString();
strImmediateTwoUp = strColName + ((row + 1) - 2).ToString();
strSum = string.Format("+SUM({0}:{1})", strImmediateTwoUp, strImmediateOneUp);
dt.Rows[row][col] = strSum;
}
else
{
dt.Rows[row][col] = Convert.ToInt32(new Random().Next(1, NumRows));
}
}
}
startsum = 1;
}
return dt;
}
private string GenerateColumnText(int num)
{
string str = "";
char achar;
int mod;
while (true)
{
mod = (num % 26) + 65;
num = (int)(num / 26);
achar = (char)mod;
str = achar + str;
if (num > 0) num--;
else if (num == 0) break;
}
return str;
}
When adding a formula to a cell you use the Formula property. When you load a range from a DataTable using LoadFromDataTable it has no way of knowing that some of the values are meant to be interpreted as formulas.
You can use LoadDataTable to populate the cells on which the formulas will operate, but for the formulas you'll need to set the Formula property.

I want to create the 'times table (2x2 = 4)' table using the GridView in Asp.net

I want to create a 9x9 GridView, list the numbers 1 through 9 in columns and rows, and then put the values ​​into an array.
I want to create it using for and Array, but I do not know what to do.
The current state is that the value is displayed below the column and all the values ​​appear only on one row.
I want to complete one program and help.
aspx.
<asp:GridView ID="GridView1" runat="server">
<Columns></Columns>
aspx.cs.
public partial class GridEX : System.Web.UI.Page{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable dt = new DataTable();
int i = 1;
if (!Page.IsPostBack)
{
for (; i <= 9; i++)
{
dt.Columns.Add(i + "단");
}
for (int k = 1; k <= 9; k++)
{
DataRow dr = dt.NewRow();
for (int m = 1; m <= 9; m++)
{ dr[m] = i; }
dt.Rows.Add(dr);
dt.Rows.Add(i * k);
}
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
}
}
What I want image:
DataTable dt = new DataTable();
dt.Columns.Add("Factor1");
dt.Columns.Add("Factor2");
dt.Columns.Add("Result");
for(int i=2; i<=9; i++)
{
for (int j=1; j<=10; j++)
{
dt.Rows.Add(i, j, i*j);
}
}
GridView1.DataSource = dt;
GridView1.DataBind();
You may have your reasons for wanting to use a Gridview here, but in my opinion, it is not the right way to achieve your goal. DataBinding is a useful tool but it does come with processing overhead, at the very least it is another iteration.
You can use a DataTable to achieve the same thing without the binding overhead.
ASPX
<asp:Table ID="MulitiplicationTable" runat="server"></asp:Table>
C#
for(int row = 0; row < 10; row++)
{
TableRow newRow = new TableRow();
MulitiplicationTable.Rows.Add(newRow);
for (int column = 0; column < 10; column++)
{
TableCell newCell = new TableCell();
newRow.Cells.Add(newCell);
//Empty cell for our first cell...
if ((row + column) == 0)
{
newCell.Text = " ";
}
//Our Column and row headers are also
//Special Cases
else if(row == 0)
{
newCell.Text = column.ToString();
newCell.CssClass = "columnHead";
}
else if(column == 0)
{
newCell.Text = row.ToString();
newCell.CssClass = "rowHead";
}
//Now do the math
else
{
newCell.Text = (row * column).ToString();
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable table9x9 = new DataTable();
if (table9x9.Columns.Count == 0)
{
for (int i = 0; i < 10; i++)
{
if (i == 0)
table9x9.Columns.Add(" ");
else
table9x9.Columns.Add(i+"");
}
}
for (int row = 1; row <= 9; row++)
{
DataRow dr = table9x9.NewRow();
for (int column = 0; column <= 9; column++)
{
if (column == 0)
dr[" "] = row;
else
dr[column + ""] = row * column;
}
table9x9.Rows.Add(dr);
}
GridView2.DataSource = table9x9;
GridView2.DataBind();
}
}
Output:

How do I dynamically set the forecolour of my column data based on the value when exporting excel using EPPLUS?

I have a set of codes to export grid view data to excel using EPPLUS. I am able to export the data to EPPLUS. But how do I export the colour of the font to excel as well? Can I set the dynamic coding for the font colour if ..... colour = green if ..... colour = red?
Thus I will need column4 to be coloured as well according to the value I set.
The below codes is how I set dynamically for gridview:
if (e.Row.RowType == DataControlRowType.DataRow)
{
TableCell cell = e.Row.Cells[16];
int Num = int.Parse(cell.Text);
if (Num >= 1&& Num <= 11)
{
cell.ForeColor = Color.Green;
}
if (Num >= 12&& Num <= 39)
{
cell.ForeColor = Color.Orange;
}
..........
}
The codes for my export:
protected void EXPORT_BUTTON_Click(object sender, EventArgs e)
{
ExcelPackage package = new ExcelPackage();
ExcelWorksheet Grid = package.Workbook.Worksheets.Add("ORSA ASSESSMENTS");
DataTable Gridview1 = new DataTable();
for (int i = 0; i < Gridview1.Columns.Count; i++)
{
Gridview1.Columns.Add("column" + i.ToString());
}
foreach (GridViewRow row in Gridview1.Rows)
{
DataRow dr = Gridview1.NewRow();
for (int j = 0; j < Gridview1.Columns.Count; j++)
{
row.Cells[j].Text = row.Cells[j].Text.Replace(" ", " ");
dr["column" + j.ToString()] = row.Cells[j].Text;
}
Gridview1.Rows.Add(dr);
}
Grid.Cells["A1"].LoadFromDataTable(Gridview1, true);
using (ExcelRange rng = Grid.Cells["A1:Z1"])
{
rng.Style.Font.Bold = true;
}
Grid.Cells[ORSA.Dimension.Address].AutoFitColumns();
var FolderPath = ServerName + DirectoryLocation + DirectoryFolder + ExportsFolder;
var filename = ExcelName + #"_" + ".xlsx";
var filepath = new FileInfo(Path.Combine(FolderPath, filename));
Response.Clear();
package.SaveAs(filepath);
Response.AddHeader("content-disposition", "attachment; filename=" + filename + ";");
Response.Charset = "";
Response.ContentType = "application/vnd.xlsx";
Response.TransmitFile(filepath.FullName);
Response.End();
}
Thus how can I do in my export codes so that I can export or set the forecolour dynamically upon exporting?
thanks
After this line
Grid.Cells["A1"].LoadFromDataTable(Gridview1, true);
Do a looping to loop the count of your DataTable
Example
protected void Page_Load(object sender, EventArgs e)
{
// Check
if (!IsPostBack)
{
DataTable dt = new DataTable();
// Create Column
for(int i = 0; i < 5; i++)
dt.Columns.Add("column" + i, typeof(int));
for (int i = 0; i < 10; i++)
dt.Rows.Add(i, i+1, i+2, i+3, i+4);
GenerateExcel(dt);
}
}
private void GenerateExcel(DataTable dt)
{
using (ExcelPackage pkg = new ExcelPackage())
{
ExcelWorksheet ws = pkg.Workbook.Worksheets.Add("Sheet1");
int num = 0;
string value = string.Empty;
ws.Cells[1, 1].LoadFromDataTable(dt, true);
// Get Your DataTable Count
int count = dt.Rows.Count;
int countCol = dt.Columns.Count;
bool isHeader = true;
for (int i = 0; i < count; i++ )
{
// Set Border
for (int j = 1; j <= countCol; j++)
{
// Set Border For Header. Run once only
if (isHeader) ws.Cells[1, j].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin, System.Drawing.Color.Black);
ws.Cells[2 + i, j].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin, System.Drawing.Color.Black);
}
// Set to false
isHeader = false;
// Cells 2 + i == Rows, Wondering start with 2 because your 1st rows is Title so 2 is the value
// Cells 2 == Column make sure your column is fix
value = ws.Cells[2 + i, 2].Value + ""; // You can use .ToString() if u sure is not null
// Parse
int.TryParse(value, out num);
// Check
if (num >= 1 && num <= 11)
ws.Cells[2 + i, 2].Style.Font.Color.SetColor(System.Drawing.Color.Green);
else if (num >= 12 && num <= 39)
ws.Cells[2 + i, 2].Style.Font.Color.SetColor(System.Drawing.Color.Orange);
}
pkg.SaveAs(new FileInfo("C:\\Test.xlsx"));
}
}

Is it possible to copy row (with data, merging, style) in Excel using Epplus?

The problem is that I need to insert data into Excel from the collection several times using a single template for the entire collection.
using (var pckg = new ExcelPackage(new FileInfo(association.TemplatePath)))
{
var workSheet = pckg.Workbook.Worksheets[1];
var dataTable = WorksheetToDataTable(workSheet);
/*Some stuff*/
FindAndReplaceValue(workSheet, dictionary, row);
}
private DataTable WorksheetToDataTable(ExcelWorksheet oSheet)
{
int totalRows = oSheet.Dimension.End.Row;
int totalCols = oSheet.Dimension.End.Column;
DataTable dt = new DataTable(oSheet.Name);
DataRow dr = null;
for (int i = 1; i <= totalRows; i++)
{
if (i > 1) dr = dt.Rows.Add();
for (int j = 1; j <= totalCols; j++)
{
if (i == 1)
dt.Columns.Add((oSheet.Cells[i, j].Value ?? "").ToString());
else
dr[j - 1] = (oSheet.Cells[i, j].Value ?? "").ToString();
}
}
return dt;
}
First picture - My template. Second - First element of collection (with data, style, merging). Third - Other elements has only data
I just made copies of rows
for (int i = 0; i < invoiceList.Count; i++)
{
workSheet.Cells[1, 1, totalRows, totalCols].Copy(workSheet.Cells[i * totalRows + 1, 1]);
}
If you want to copy range just use :
workSheet.Cells["A1:I1"].Copy(workSheet.Cells["A4:I4"]);

First column in Excel should continuously repeated in datagrid

I have an Excel file with 2 columns [file in my pc]? Now iam getting 2 columns with 8 rows with below code.but continuously i should get 5*2=10 more of same columns with 8 rows in datagridview.
I have written the code which gives result only 2 columns but I should get 10 more columns with 8 rows.below is my code
for (int Cnum = 1; Cnum <= ShtRange.Columns.Count; Cnum++)
{
dt.Columns.Add((ShtRange.Cells[1, Cnum] as Excel.Range).Value2.ToString());
}
for (int Rnum = 2; Rnum <= 9; Rnum++)
{
dt.Rows.Add((ShtRange.Cells[Rnum, 1] as Excel.Range).Value2.ToString(),
(ShtRange.Cells[Rnum, 1] as Excel.Range).Value2.ToString());
}
}
for (int i = 0; i < 13; i++)
{
DataGridViewTextBoxCell txtbx = new DataGridViewTextBoxCell();
DataGridViewColumn txcol = new DataGridViewColumn();
txcol.CellTemplate = txtbx;
txcol.HeaderText = "column" + i.ToString();
dg1.Columns.Add(txcol);
}
dg1.Rows.Add(8);
int dgRw, dgCol;
dgRw = dgCol = 0;
foreach (DataRow dr in dt.Rows)
{
dg1[dgCol, dgRw].Value = dr[0].ToString();
dgRw++;
if (dgRw == 8)
{
dgCol++;
dgRw = 0;
}

Categories

Resources