Creating New Excel Sheet name using C# - c#

I have here the codes where I'am confuse with
What I want is to create a program where in when I have 2 parent keys who both have 15 childs.. It will authomatically show its attributes on my excel sheet but then, the first keys can be created successfully.. apparently, the second keys is having an error since it is trying to save on the same worksheet as keys 1. Do anyone of you know how to use GetSheetNo? or CopySheet?
int cntAddMember = 0;
int cntPage = 0;
string sheetName = dbReportDef.WorkSheet;
string copyBaseSheet = "TEMP" + sheetName;
string boforeSheet = sheetName;
int boforeSheetPos = this.excel.GetSheetNo(boforeSheet);
used to check the value of the sheetfirst before creating a new one,
if (dbReportDef.IsAddMember)
{
if (this.detailNum < 0) { this.detailNum = GetDetailLine(sheetName, dbReportDef.CellNo); }
if (!this.excel.ExistSheet(copyBaseSheet))
{ this.excel.CopySheet(sheetName, copyBaseSheet, boforeSheetPos); }
}
thanks :)

Related

How to access 'Resize Table' of 'Table Design' tab in excel with Open XML SDK in .NET C#

I'm trying to write to an existing excel template (.xlsx) and saving it as a new file using Open XML SDK in .NET C#. I have a requirement to change the table design and resize the table programmatically. I'm not able to access the 'Resize Table' property using Open XML.
Manually we can access it by going to 'Table Design' tab and then selecting ' Resize Table'. Please refer to the below screenshot
Any help is greatly appreciated. Thanks!
First Get Your table By name ( if just one table you can get the
first)
then Update the reference ( size of the table) and
save the workSheet.
the table size refrenace is just a string ex. A1:H5
you need to change the H5 to H15 to resize the table to add 10 rows more :)
Just Sample code
var tableDefinitionPart = worksheetPart.TableDefinitionParts.Where(table=>table.Table.DisplayName== "Your table name").FirstOrDefault();
// OR var tableDefinitionPart = worksheetPart.TableDefinitionParts.FirstOrDefault();
if (tableDefinitionPart != null)
{
UpdateTableDefinitionPart(tableDefinitionPart, newTotalRows);
}
workSheet.Save();
public void UpdateTableDefinitionPart(TableDefinitionPart tableDefinitionPart, uint rowsCount)
{
var tableSize = tableDefinitionPart.Table.Reference;
string newSize = tableSize.UpdateRowsTo(rowsCount);
tableDefinitionPart.Table.Reference = newSize;
tableDefinitionPart.Table.AutoFilter.Reference = newSize;
}
*************************************************************************************
public static string UpdateRowsTo(this StringValue tableReference, uint rows)
{
string result = tableReference.Value.Trim();
var parts = result.Split(':');
Regex regex = new Regex("[a-zA-Z]+");
Match match = regex.Match(parts[1]);
result = $"{parts[0]}:{match.Value}{rows}";
return result;
}
OR
***************************************************************************************
public static string UpdateRowsTo2(this StringValue tableReference, uint rows)
{
string result = tableReference.Value.Trim();
int index = result.Length - 1;
while (!string.IsNullOrWhiteSpace(result) && Char.IsDigit(result[--index]))
{
}
result = result.Substring(0, index + 1) + rows;
return result;
}

Error when writing data to Excel using OleDb C# : this table contains cells that are outside the range of cells defined in this spreadsheet

I don't know why I keep getting the error:
'This table contains cells that are outside the range of cells defined
in this spreadsheet'
I'm trying to write data which is received serially from a sensor to an Excel document. I've tried using both the "INSERT INTO" and "UPDATE" statements, both of which don't seem to work. I'm hoping someone could shed some light on what could be the problem and provide a hint for a possible solution.
I finally managed to partially fix the problem by tweaking the code a lot but now the problem is that the same error occurs but just after the program writes the data into the first and second row of the excel file, when its about the write in the third row, it outputs the error instead; note however this problem occurs for excel files with .xls extensions.
But when I tried it with the .xlsx files, it seems that the program is only able to write in the first row before outputting the same error when it attempts to write in the second row. Any suggestions, to what I may have done wrong?
Thanks.
Below is the code:
private void ProcessRxdSerialData(string rxdSerialData, int rxdSerialVal)
{
try
{
if (!string.IsNullOrEmpty(rxdSerialData))
{
Console.WriteLine(rxdSerialData);
HandleRxdSerialDataResponse(rxdSerialData);
TimeElapsed = TimeElapsed + 1;
m_mainForm.PlotGraphs(rxdSerialVal, TimeElapsed);
string columnSelect = "A";
m_mainForm.XlsxWrite(rxdSerialData, m_mainForm.DataStorageFileLocation, columnSelect);
}
} //try
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public void XlsxWrite(string rxdSerialData, string dataStorageLocation, string columnSelect)
{
try
{
Invoke(new MethodInvoker(
delegate
{
if ((checkBoxEnableWriteToExcel.Checked) &&
(!string.IsNullOrEmpty(textBoxDataStorageLocation.Text)))
{
RowCount = RowCount + 1;
WriteRxdSerialDataToExcel(rxdSerialData, dataStorageLocation, RowCount, columnSelect);
}
else
{
RowCount = 0;
}
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public void WriteRxdSerialDataToExcel(string rxdSerialData, string dataStorageLocation, int timeElapse, string columnSelect)
{
int row = timeElapse;
string column = columnSelect;
//Converting Row integer to string
string rowStr = row.ToString();
//Open Excel File to conduct Write/Update process
string fileLocation = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + dataStorageLocation +
#";Extended Properties=""Excel 12.0; HDR=No;IMEX=3;ImportMixedTypes=Text;TypeGuessRows=0"""; //for reading data IMEX = 1, for writting data IMEX = 3
OleDbConnection pathConnection = new OleDbConnection(fileLocation);
pathConnection.Open();
//write the data into the Excel Spread sheet
string rowColumnCoordinate = String.Concat(column, rowStr);
string excelWrite = String.Format("UPDATE [Sheet1${0}:{0}] SET F1='{1}'", rowColumnCoordinate, rxdSerialData);
OleDbCommand command = new OleDbCommand(excelWrite, pathConnection);
command.ExecuteNonQuery();
pathConnection.Close();
}

EPPlus - LoadFromCollection - Text converted to number

I am writing a program in C# that needs to export a List<MyObject> into Excel and I'm using EPPlus for doing so.
My challenge is that my object has a property:
string Prop1 { get; set; }
And, one of the values I need to export has a value that, for example, is of the form of Prop1 = "123E4".
The challenge is that the EPPlus LoadFromCollection method exports this to Excel, but Excel converts it into a number using scientific notation (Outputted value = 1.23E+06 or 1230000).
I've tried setting the entire column to .Style.Numberformat.Format = "#" (and any other style I could think of) and I've even tried setting the style before and after the LoadFromCollection method is called.
I also tried preceding the string with a ' character, but that actually keeps that character in each cell within that column which then makes the values incorrect for analysis.
I'm playing around with converting my List to a DataTable so as to use the LoadFromDataTable method, but even that seems to not be working.
Any ideas / suggestions on how I can export this as pure text
If you have string that look like numbers Excel will warn you with those green trigangles in the corner of the cells. This is assuming you are converting the numbers (if they are numbers) to string using something like .ToString(). There is not way to get around this in Excel but you could turn on the disable warning message for that condition using XML maniulation since EPPlus does not have the ability natively.
Something like this would do it:
public class TestObject
{
public int Col1 { get; set; }
public int Col2 { get; set; }
public string Col3 { get; set; }
}
[TestMethod]
public void Number_String_Test()
{
//Throw in some data
var datalist = new List<TestObject>();
for (var i = 0; i < 10; i++)
{
datalist.Add(new TestObject
{
Col1 = i,
Col2 = i *10,
Col3 = (i*10) + "E4"
});
}
//Create a test file
var fi = new FileInfo(#"c:\temp\numtest.xlsx");
if (fi.Exists)
fi.Delete();
using (var pck = new ExcelPackage(fi))
{
var worksheet = pck.Workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromCollection(datalist);
//This would be the variable drawn from the desired cell range
var range = "C1:C11";
//Get reference to the worksheet xml for proper namspace
var xdoc = worksheet.WorksheetXml;
//Create the import nodes (note the plural vs singular
var ignoredErrors = xdoc.CreateNode(XmlNodeType.Element, "ignoredErrors", xdoc.DocumentElement.NamespaceURI);
var ignoredError = xdoc.CreateNode(XmlNodeType.Element, "ignoredError", xdoc.DocumentElement.NamespaceURI);
ignoredErrors.AppendChild(ignoredError);
//Attributes for the INNER node
var sqrefAtt = xdoc.CreateAttribute("sqref");
sqrefAtt.Value = range;
var flagAtt = xdoc.CreateAttribute("numberStoredAsText");
flagAtt.Value = "1";
ignoredError.Attributes.Append(sqrefAtt);
ignoredError.Attributes.Append(flagAtt);
//Now put the OUTER node into the worksheet xml
xdoc.LastChild.AppendChild(ignoredErrors);
pck.Save();
}
}

Set Print Area - OpenXML with Excel

Does anybody know how to set print area through OpenXML SDK in Excel?
I've tried using the following code:
public void XLUpdateDefinedName(string fileName, string definedName, string newRange)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
{
WorkbookPart wbPart = document.WorkbookPart;
var definedNames = wbPart.Workbook.Descendants<DefinedNames>().FirstOrDefault();
DefinedName name = definedNames.Descendants<DefinedName>().Where(m => m.Name == definedName).Single();
UInt32Value locSheetId = name.LocalSheetId;
name = null;//.Remove();
wbPart.Workbook.Save();
name = new DefinedName() { Name = definedName, LocalSheetId = locSheetId , Text = newRange}
;
wbPart.Workbook.Save();
//newDefinedName.Text = newRange;
//definedNames.Append(newDefinedName);
}
}
UPDATE:
I continue to receive an error from excel saying there is unreadable content in file with the following code.
public void XLUpdateDefinedName(string fileName, string definedName, string newRange, string sheet, UInt32Value localId)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
{
String sheetName = sheet;
string topLeft = newRange.Split(':').First();
string bottomRight = newRange.Split(':').Last();
WorkbookPart wbPart = document.WorkbookPart;
var definedNames = wbPart.Workbook.Descendants<DefinedNames>().FirstOrDefault();
var nameCollection = definedNames.Descendants<DefinedName>().Where(m => m.Text.StartsWith(sheetName));
DefinedName name = nameCollection.Count() > 0 ? nameCollection.First() : null;
UInt32Value locSheetId;
if (name != null)
{
locSheetId = name.LocalSheetId;
name.Remove();
wbPart.Workbook.Save();
}
else
{
locSheetId = localId;
}
name = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = locSheetId};
name.Text = String.Format("{0}!{1}:{2}", sheetName,topLeft,bottomRight);
definedNames.Append(name);
wbPart.Workbook.Save();
}}
newRange is of the form ( $A$10:$C$15 )
I've found some information about a method that seems not to be using Interop. You can try something like:
//load the work book
...
myWorkBook.Worksheets.First().PageSetup.PrintAreas.Add("A1:F40");
//save the workbook
//...
See if this helps. I haven't tried it myself yet, but I'm going to verify it.
UPDATE:
The first method seems to require an additional library. You can get it from here:
http://closedxml.codeplex.com/. I haven't used it myself, so I cannot assure you it works correctly.
Pure OpenXML solution
I've managed to change the print area by manually modifying the xlsx file contents in notepad editor.
In C# you should try to use the follwoing method (it sets printing area to A1:G19):
//first you need to get reference to your workbook, but I assume you already have this
//...
//then you can add an information about desired print area
DefinedNames definedNames = new DefinedNames();
DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)0U };
printAreaDefName.Text = "Worksheet1!$A$1:$G$19";
definedNames.Append(printAreaDefName);
//then you should append the created element to your workbook
//...
workbook1.Append(definedNames);
The thing you need to change is line: printAreaDefName.Text = "Worksheet1!$A$1:$G$19";.
You should change the Text value to contain information in format: [worksheet_name]![top-left corner of print area]:[bottom-right corner of print area]. It should set your print area to a rectangle with upper-left and bottom-right corners as specified.
If you want to specify print areas for different worksheets, try to add multiple DefinedName objects:
DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)0U };
printAreaDefName.Text = "Worksheet1!$A$1:$G$19";
definedNames.Append(printAreaDefName);
DefinedName printAreaDefName2 = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)1U };
printAreaDefName2.Text = "Worksheet2!$B$1:$H$23";
definedNames.Append(printAreaDefName2);
DefinedName printAreaDefName3 = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = (UInt32Value)2U };
printAreaDefName3.Text = "Worksheet3!$A$1:$J$10";
definedNames.Append(printAreaDefName3);
I also recommend using OpenXML SDK 2.0 Productivity Tool. It allows you to show the contents of a chosen OpenXML file, compare files, validate a file and even show a C# code that you would write in order to recreate the file programatically :).
You can download it from here:
http://www.microsoft.com/download/en/details.aspx?id=5124
UPDATE II:
I've corrected a mistake in format of the print area value string. Sorry for the confusion.
I've also took the code you posted and created a method based on it. It works correctly and after modifying the print area I can open the file in Excel without issues. The code assumes that a print range is already defined and you are now just changing it, but it can be modified to add new print range as well.
Here's the code:
private void OpenXmlFileHandling(String fileName)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
{
//some sample values
String definedName = "Worksheet3";
String topLeft = "$A$3";
String bottomRight = "$D$7";
WorkbookPart wbPart = document.WorkbookPart;
var definedNames = wbPart.Workbook.Descendants<DefinedNames>().FirstOrDefault();
var namesCollection = definedNames.Descendants<DefinedName>().Where(m => m.Text.StartsWith(definedName));
DefinedName name = namesCollection != null ? namesCollection.First() : null;
UInt32Value locSheetId;
//we assume that name is not null, because print range for this worksheet was defined in the source template file
//if name was null, we should probably just assign to locSheetId a number definedNames.Count() + 1 and not remove the name node
locSheetId = name.LocalSheetId;
name.Remove();
wbPart.Workbook.Save();
name = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = locSheetId, Text = String.Format("{0}!{1}:{2}", definedName, topLeft, bottomRight) };
definedNames.Append(name);
wbPart.Workbook.Save();
}
}
I put the values of worksheet name and print area range inside the method, so you can see what kind of values they should have. I hope this helps.
Let me explain my case: I have excel workbook with following sheets (T1,I1,M1). Now my requirement was based on some condition T1,I1,M1 will be copied to same excel workbook multiple times e.g. T2,I2,M2, T3,I3,M3 and so on. For me I2,M2 did not have any issues with Print area but for copied sheet T2,T3... had issue. since it had huge data. excel column goes upto "AG". So here is what i did in code
Once the new sheet is added to workbook
sheets.Append(copiedSheet);
first get the current sheet count
var count = sheets.Count();
Get the sheet count, this will be used in LocalsheetId as printarea setting.
Only for copied techical sheet the print area was not set properly. Hence need to be set correctly.
DefinedName printAreaDefName = new DefinedName() { Name = "_xlnm.Print_Area", LocalSheetId = Convert.ToUInt32(count) };
Be care full with defName.Text the format is 'T1'!$A$1:$AG$19
printAreaDefName.Text = "'" + copiedSheet.Name + "'!$A$1:$AG$22";
workbookPart.Workbook.DefinedNames.Append(printAreaDefName);
workbookPart.Workbook.Save();
There was no need for me to add new Definedname in DefinedNames collection. So I just added to workbook definedNames collection and it worked.

While Reading data from a .xlsx file

string Code = "";
if (fileUp.HasFile)
{
string Path = fileUp.PostedFile.FileName;
// initialize the Excel Application class
ApplicationClass app = new ApplicationClass();
// create the workbook object by opening the excel file.
Workbook workBook = app.Workbooks.Open(Path, 0, true, 5, "", "", true,
XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
// Get The Active Worksheet Using Sheet Name Or Active Sheet
Worksheet workSheet = (Worksheet)workBook.ActiveSheet;
int index = 0;
// This row,column index should be changed as per your need.
// that is which cell in the excel you are interesting to read.
object rowIndex = 2;
object colIndex1 = 1;
object colIndex2 = 2;
object colIndex3 = 3;
object colIndex4 = 4;
object colIndex5 = 5;
object colIndex6 = 6;
object colIndex7 = 7;
try
{
while (((Range)workSheet.Cells[rowIndex, colIndex1]).Value2 != null)
{
rowIndex = 2 + index;
//string QuestionCode = (index + 1).ToString();
string QuestionCode = ((Range)workSheet.Cells[rowIndex, colIndex1]).Value2.ToString();
string QuestionText = ((Range)workSheet.Cells[rowIndex, colIndex2]).Value2.ToString();
string CorrectAnswer = ((Range)workSheet.Cells[rowIndex, colIndex3]).Value2.ToString();
string ChoiceA = ((Range)workSheet.Cells[rowIndex, colIndex4]).Value2.ToString();
string ChoiceB = ((Range)workSheet.Cells[rowIndex, colIndex5]).Value2.ToString();
string ChoiceC = ((Range)workSheet.Cells[rowIndex, colIndex6]).Value2.ToString();
string ChoiceD = ((Range)workSheet.Cells[rowIndex, colIndex7]).Value2.ToString();
// string ChoiceE = ((Excel.Range)workSheet.Cells[rowIndex, colIndex7]).Value2.ToString();
newQuestionElement = new XElement("Question");
XElement optionElement = new XElement(QuestionElement.Option);
questionType = ddlQusType.SelectedValue.ToByte();
if (!string.IsNullOrEmpty(QuestionText))
newQuestionElement.Add(new XElement(QuestionElement.QuestionText, QuestionText));
else
{
//lblMessage.Text = "Missing question in Qus No.: " + i;
break;
}
newQuestionElement.Add(new XElement(QuestionElement.QuestionType, questionType));
//newQuestionElement.Add(new XElement(QuestionElement.Randomize, chbRandomizeChoice.Checked));
newQuestionElement.Add(new XElement(QuestionElement.Answer, CorrectAnswer));
if (ChoiceA.Trim() != string.Empty)
optionElement.Add(new XElement("A", ChoiceA));
if (ChoiceB.Trim() != string.Empty)
optionElement.Add(new XElement("B", ChoiceB));
if (ChoiceC.Trim() != string.Empty)
optionElement.Add(new XElement("C", ChoiceC));
if (ChoiceD.Trim() != string.Empty)
optionElement.Add(new XElement("D", ChoiceD));
newQuestionElement.Add(optionElement);
index++;
saveData(QuestionCode.ToString());
I am using this code to retrieve the data from .xlsx file.
But if the file has any special characters in it, it is showing it as different, like so
The set S = {1,2,33……….12} is to be partitioned into three sets
A,B,C of equal size. Thus, `A U B U C = S,`
The set S = {1,2,33……….12} is to be partitioned into three sets
A,B,C of equal size. Thus, `A È B È C = S,`
Looks like an encoding issue.
I use to have this issue after reading Excel into a data table and then serializing the data table to a file.
Every time I would read the data back in from the serialized file, some symbols would be replaced with funny A's and E's.
I discovered the problem was with the encoding I was using. I then started to store excel data using Unicode encoding and have never encounter another symbol problem with Excel data again.
I hope this helps...

Categories