Quantcast
Channel: ClosedXML - The easy way to OpenXML
Viewing all 1877 articles
Browse latest View live

Created Unassigned: Bug on sorting Data [9255]

$
0
0
Hi, when I try to sort the data based on a column that has a formula, sorting does not work. It seems that the data are sorted by alphabetical sorting of the formula in the cell.
Thanks, Simona

New Post: Excessive memory consumption on SaveAs()

$
0
0
Hello , I need to export the result of a sql query on an Excel spreadsheet and to do this I use this library. Unfortunately I seem to have found (thanks to a memory profiler) an abnormal consumption of memory.
I considered a query of 30000 rows and 30 columns that products an excel sheet of 4.5 MB. After generating the workbook (but not saved) the memory is increased of 123 MB of which 93 MB for objects which belong to the library ClosedXML and 30 MB for objects such as strings, datetime and numbers. Saving this file on disk (istruction .SaveAs (filename) ) there is a considerable spike in memory (about 4 times the size of worbook, but it is not linear) and then invoking the garbage collector is released. Is it possible doing somehow for limit this peak and avoid an ​​Out-of -memory error?
Thanks, Simona

Created Unassigned: system.memoryout of exception [9259]

$
0
0
Hi

I exporting around 50,000 rows to excel. I am using row grouping. I have lot of groupings. It works well for 20k rows but memory spikes a lot to atleast 1 gb. Its happening on the windows 2008 r2 servers with 24 gb ram

My data is lot of processed data before passing it to worksheet. This is the reason i am unable to provide data. Please let me know if there are any corrections i need to make to get it work

Thanks

using (var workbook = new ClosedXML.Excel.XLWorkbook())
{
var ws = workbook.Worksheets.Add(dt);
if (indentLevel == 2)
{

ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Red;
}
else if (indentLevel == 3)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Blue;
}
else if (indentLevel == 4)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.ShockingPink;
}
else if (indentLevel == 5)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Green;
}
else if (indentLevel == 6)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Maroon;
}
else if (indentLevel == 7)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Purple;
}
else if (indentLevel == 8)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Orange;
}
}
catch (Exception ex)
{
string script = "<script type=\"text/javascript\">alert('No results to export to excel');</script>";
ClientScript.RegisterClientScriptBlock(this.GetType(), "Alert", script);
break;
}
}

for (int i = 0; i < dt.Rows.Count; i++)
{
ws.Cell(i + 2, 17).Style.Font.FontColor = XLColor.Blue;
ws.Cell(i + 2, 17).Style.Font.Underline = XLFontUnderlineValues.Single;
ws.Cell(i + 2, 17).Hyperlink = new XLHyperlink(ConfigurationSettings.AppSettings["url"].ToString() + "displaybss.aspx?partnumber=" + dt.Rows[i]["Prt No"].ToString() + "&partrev=" + dt.Rows[i]["Rev"].ToString());
}

//ws.Columns().AdjustToContents();
ws.Columns(maxlevel + 1, 15).Hide();
ws.Outline.SummaryHLocation = XLOutlineSummaryHLocation.Left;
ws.Outline.SummaryVLocation = XLOutlineSummaryVLocation.Top;


HttpResponse response = Response;
response.Clear();
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
response.AddHeader("content-disposition", "attachment;filename=Results.xlsx");

//MemoryStream MyMemoryStream = new MemoryStream();
using (MemoryStream MyMemoryStream = new MemoryStream())
{

workbook.SaveAs(MyMemoryStream);
response.Charset = "";
response.AddHeader("Content-Length", MyMemoryStream.Length.ToString());
response.BinaryWrite(MyMemoryStream.GetBuffer());
}

response.Flush();
response.OutputStream.Close();
response.End();
workbook.Dispose();
ws.Dispose();
ws = null;
GC.Collect();
GC.SuppressFinalize(workbook);
HttpContext.Current.ApplicationInstance.CompleteRequest();
}

}

Commented Issue: Adjusting to Content does not work on Windows Azure Websites [8602]

$
0
0
Adjusting column widths based on content fails on Windows Azure Websites because it seems that the functionality provided by [System.Windows.Forms.TextRenderer](http://msdn.microsoft.com/en-us/library/system.windows.forms.textrenderer.aspx), which is used for measuring string widths, is missing. TextRenderer returns arbitrary output (width > 1,000,000 for the string "hello") instead of real values.

The issue can be resolved by using GDI+ instead of GDI, hence using [System.Drawing.Graphics.MeasureString](http://msdn.microsoft.com/en-us/library/system.drawing.graphics.measurestring.aspx).

The following code snippet demonstrates a rough idea how text measuring using GDI+ could be implemented. Note however that always bold fonts are assumed and that rich text is not handled appropriately.

```
public static void AdjustToContentsGDIPlus(this IXLColumn column)
{
using (var bitmap = new Bitmap(1, 1))
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.TextRenderingHint = TextRenderingHint.AntiAlias;

var fontCache = new Dictionary<IXLFontBase, Font>();
var width = column.CellsUsed()
.Select(c => new {Font = GetFont(c.Style.Font, fontCache), Value = c.GetFormattedString()})
.Max(c => MeasureText(graphics, c.Value, c.Font));

column.Width = width;
}
}

private static Font GetFont(IXLFontBase fontBase, IDictionary<IXLFontBase, Font> fonts)
{
Font font;

if (!fonts.TryGetValue(fontBase, out font))
{
font = new Font(fontBase.FontName, (float) fontBase.FontSize, FontStyle.Bold);
fonts.Add(fontBase, font);
}

return font;
}

private static double MeasureText(Graphics graphics, string text, Font font)
{
var size = graphics.MeasureString(text, font, Int32.MaxValue, StringFormat.GenericTypographic);

// calculation taken from FontBaseExtensions.GetWidth method
var width = (((size.Width / (double)7) * 256) - (128 / 7)) / 256;
width = (double) Decimal.Round((decimal)width + 0.2M, 2);

return width;
}
```
Comments: ** Comment from web user: paaland **

This is a huge issue for me. This single issue is preventing me from going live on Azure.

Created Issue: Unable to cast object of type 'ClosedXML.Excel.XLFont' to type 'ClosedXML.Excel.XLStyle' [9260]

$
0
0
Hi all,

###The Background
I'm in a bit of a high pressure situation (so sorry if I'm short in this message) and trying to figure out something with the ClosedXML library.

We have an invoice processor that opens an invoice, and uses various validators to check items.

__Most of the time, these rows process fine and I receive successful results.__ However, whenever there's a validation error at the row level (e.g. "this field is supposed to be a date but you entered a non-date", we throw a fluent validation exception with the error message to pass back to the caller (this runs in a WebAPI).

What I can't understand is that, I have the validation error and I'm ready to pass it back, and I can follow the stack trace and see exactly that error message. However, somewhere at the last second, some other exception comes up that says:

>Unable to cast object of type 'ClosedXML.Excel.XLFont' to type 'ClosedXML.Excel.XLStyle'.

I'm hoping to determine how to trap this error, as I've already received the information I receive correctly and just wish to pass back the value I already have.

**I know this is likely something that I'm doing dumb, so please feel free to point out things that you might think I've already checked.**

###Theories
It appears that something may still be hanging around in memory or trying to process, as the error occurs when serializing my final object to JSON, despite the object itself being a purely business object and having nothing to do with the Excel file.

FYI, I have tried this with spreadsheets that are completely blank, spreadsheets with the formatting removed, etc. etc. -- there should be neither fonts nor styles in these workbooks and yet I get an error about the conversion.

##The Code

I'll attempt to explain what we're doing with some code below.

In our `/api/StandardInvoiceDetailsFile` controller, where users submit the file, we:

Save the file:

```C#
var path = HostingEnvironment.MapPath(string.Format("~/App_Data/import/{0}.xlsx", DateTime.Now.Ticks));
Debug.Assert(path != null, "path != null");
file.SaveAs(path);
```

then we start the processing:

```C#
//the happy path -- process a file and return an HttpResponseMessage with the appropriate information.
try
{
IList<IStandardInvoiceDetailItem> processResult;
workbook = new XLWorkbook(path);

processResult =
new InvoiceProcessorFactory(this._clientSiteID, this._firmID).GetInvoiceProcessorInstance()
.ProcessInvoice(workbook);

}

//uh-oh, their workbook items were invalid in some way. Format and return an http OK but with a collection of validation errors and error messages.
catch (FluentValidationException validationEx)
{
workbook.Dispose();
var validationErrors = validationEx.Data["ValidationErrors"] as IList<ValidationFailure>;

return this.CreateResult(false, validationEx.Message, HttpStatusCode.OK, new List<IStandardInvoiceDetailItem>(), validationErrors.ToList());
}
```
This first step gets an invoice processor based on a client site ID and then processes the workbook that is passed in (a ClosedXML XLWorkbook in memory.)

The part where the is actually processed is below, the "ProcessInvoice" method of the invoice processor:

```C#
public IList<IStandardInvoiceDetailItem> ProcessInvoice(IXLWorkbook workbookToValidate)
{
if (workbookToValidate == null) {throw new ArgumentNullException("workbookToValidate");}
_workbookToValidate = workbookToValidate;
this.ValidateWorkbook();
this.ValidateWorksheet();

_invoiceDetailItems = this.ValidateRowsAndReturnBusinessObjects();

this.ValidateBusinessObjects(_invoiceDetailItems);


// If all's well, return the business objects.
return _invoiceDetailItems;
}
```

The exception is initially raised (correctly) in `this.ValidateRowsAndReturnBusinessObjects()`, which does the following:

```C#
var invoiceDetailItems = new List<IStandardInvoiceDetailItem>();
foreach (var row in this._workbookToValidate.Worksheet(1).RowsUsed())
{
// we don't need to worry about the header columns, hence row > 1
if (row.RowNumber() > 1 && !row.IsEmpty())
{
var rowResult = this._rowsValidator.Validate(row);
if (!rowResult.IsValid)
{
var rowValidationErrorMessage = string.Format(
"Row {0} is invalid. Validation errors:", row.RowNumber());
throw new FluentValidationException(rowValidationErrorMessage, rowResult.Errors);
}

try
{
var newItem = new StandardInvoiceDetailRow()
{
ClaimantName = row.Cell("A").GetValue<string>(),
ClaimantId = row.Cell("B").GetValue<int>(),
Matter = row.Cell("C").GetValue<string>(),
InvoiceDate = row.Cell("D").GetValue<DateTime>(),
InvoiceNumber = row.Cell("E").GetValue<string>(),
Fees = row.Cell("F").GetValue<decimal>(),
Costs = row.Cell("G").GetValue<decimal>(),
Adjustments = row.Cell("H").GetValue<decimal>(),
Total = row.Cell("I").GetValue<decimal>()
};
invoiceDetailItems.Add(newItem);
}

catch (Exception e)
{
throw new Exception("An exception occurred while trying to creatre a business object from an excel row.", e);
}
}
}

return invoiceDetailItems;
}
```

The `RowsValidator` uses FluentValidation to do the following:

```C#
public class InvoiceDetailsWorksheetRowValidator : AbstractValidator<IXLRow>, IRowsValidator
{
public InvoiceDetailsWorksheetRowValidator()
{
this.RuleFor(x => x.Cell("B"))
.Must(ExcelValidationHelpers.BeAnInt).WithMessage("ClaimantID column value is not a valid number.")
.OverridePropertyName("ClaimantIDColumn");

this.RuleFor(x => x.Cell("D"))
.Must(ExcelValidationHelpers.BeADate).WithMessage("InvoiceDate column value is not a valid date.")
.OverridePropertyName("InvoiceDateColumn");

this.RuleFor(x => x.Cell("F"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Fees column value is not a valid decimal.")
.OverridePropertyName("FeesColumn");

this.RuleFor(x => x.Cell("G"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Costs column value is not a valid decimal.")
.OverridePropertyName("CostsColumn");

this.RuleFor(x => x.Cell("H"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Adjustments column value is not a valid decimal.")
.OverridePropertyName("AdjustmentsColumn");

this.RuleFor(x => x.Cell("I"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Total column value is not a valid decimal.")
.OverridePropertyName("TotalColumn");
}


}
```


My Excel Validation helpers are as follows:
```C#
public static bool BeADecimal(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<decimal>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

public static bool BeADate(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<DateTime>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

public static bool BeALong(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<long>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

public static bool BeAnInt(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<int>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

}
```

##I know it's a lot -- please ask questions!

The complicated nature of the code means it's tough for me to succinctly show the problem, especially since it involves an exception that I can't (yet) trap or trace in any way. I will do my best to rip this code out and get it into an exe of some kind that can be studied. I am happy to answer any questions you may have.

Edited Issue: Unable to cast object of type 'ClosedXML.Excel.XLFont' to type 'ClosedXML.Excel.XLStyle' [9260]

$
0
0
Hi all,

###The Background
I'm in a bit of a high pressure situation (so sorry if I'm short in this message) and trying to figure out something with the ClosedXML library.

We have an invoice processor that opens an invoice, and uses various validators to check items.

__Most of the time, these rows process fine and I receive successful results.__ However, whenever there's a validation error at the row level (e.g. "this field is supposed to be a date but you entered a non-date", we throw a fluent validation exception with the error message to pass back to the caller (this runs in a WebAPI).

What I can't understand is that, I have the validation error and I'm ready to pass it back, and I can follow the stack trace and see exactly that error message. However, somewhere at the last second, some other exception comes up that says:

>Unable to cast object of type 'ClosedXML.Excel.XLFont' to type 'ClosedXML.Excel.XLStyle'.

I'm hoping to determine how to trap this error, as I've already received the information I receive correctly and just wish to pass back the value I already have.

**I know this is likely something that I'm doing dumb, so please feel free to point out things that you might think I've already checked.**

###Theories
It appears that something may still be hanging around in memory or trying to process, as the error occurs when serializing my final object to JSON, despite the object itself being a purely business object and having nothing to do with the Excel file.

FYI, I have tried this with spreadsheets that are completely blank, spreadsheets with the formatting removed, etc. etc. -- there should be neither fonts nor styles in these workbooks and yet I get an error about the conversion.

##The Code

I'll attempt to explain what we're doing with some code below.

In our `/api/StandardInvoiceDetailsFile` controller, where users submit the file, we:

Save the file:

```C#
var path = HostingEnvironment.MapPath(string.Format("~/App_Data/import/{0}.xlsx", DateTime.Now.Ticks));
Debug.Assert(path != null, "path != null");
file.SaveAs(path);
```

then we start the processing:

```C#
//the happy path -- process a file and return an HttpResponseMessage with the appropriate information.
try
{
IList<IStandardInvoiceDetailItem> processResult;
workbook = new XLWorkbook(path);

processResult =
new InvoiceProcessorFactory(this._clientSiteID, this._firmID).GetInvoiceProcessorInstance()
.ProcessInvoice(workbook);

}

//uh-oh, their workbook items were invalid in some way. Format and return an http OK but with a collection of validation errors and error messages.
catch (FluentValidationException validationEx)
{
workbook.Dispose();
var validationErrors = validationEx.Data["ValidationErrors"] as IList<ValidationFailure>;

return this.CreateResult(false, validationEx.Message, HttpStatusCode.OK, new List<IStandardInvoiceDetailItem>(), validationErrors.ToList());
}
```
This first step gets an invoice processor based on a client site ID and then processes the workbook that is passed in (a ClosedXML XLWorkbook in memory.)

The part where the is actually processed is below, the "ProcessInvoice" method of the invoice processor:

```C#
public IList<IStandardInvoiceDetailItem> ProcessInvoice(IXLWorkbook workbookToValidate)
{
if (workbookToValidate == null) {throw new ArgumentNullException("workbookToValidate");}
_workbookToValidate = workbookToValidate;
this.ValidateWorkbook();
this.ValidateWorksheet();

_invoiceDetailItems = this.ValidateRowsAndReturnBusinessObjects();

this.ValidateBusinessObjects(_invoiceDetailItems);


// If all's well, return the business objects.
return _invoiceDetailItems;
}
```

The exception is initially raised (correctly) in `this.ValidateRowsAndReturnBusinessObjects()`, which does the following:

```C#
var invoiceDetailItems = new List<IStandardInvoiceDetailItem>();
foreach (var row in this._workbookToValidate.Worksheet(1).RowsUsed())
{
// we don't need to worry about the header columns, hence row > 1
if (row.RowNumber() > 1 && !row.IsEmpty())
{
var rowResult = this._rowsValidator.Validate(row);
if (!rowResult.IsValid)
{
var rowValidationErrorMessage = string.Format(
"Row {0} is invalid. Validation errors:", row.RowNumber());
throw new FluentValidationException(rowValidationErrorMessage, rowResult.Errors);
}

try
{
var newItem = new StandardInvoiceDetailRow()
{
ClaimantName = row.Cell("A").GetValue<string>(),
ClaimantId = row.Cell("B").GetValue<int>(),
Matter = row.Cell("C").GetValue<string>(),
InvoiceDate = row.Cell("D").GetValue<DateTime>(),
InvoiceNumber = row.Cell("E").GetValue<string>(),
Fees = row.Cell("F").GetValue<decimal>(),
Costs = row.Cell("G").GetValue<decimal>(),
Adjustments = row.Cell("H").GetValue<decimal>(),
Total = row.Cell("I").GetValue<decimal>()
};
invoiceDetailItems.Add(newItem);
}

catch (Exception e)
{
throw new Exception("An exception occurred while trying to creatre a business object from an excel row.", e);
}
}
}

return invoiceDetailItems;
}
```

The `RowsValidator` uses FluentValidation to do the following:

```C#
public class InvoiceDetailsWorksheetRowValidator : AbstractValidator<IXLRow>, IRowsValidator
{
public InvoiceDetailsWorksheetRowValidator()
{
this.RuleFor(x => x.Cell("B"))
.Must(ExcelValidationHelpers.BeAnInt).WithMessage("ClaimantID column value is not a valid number.")
.OverridePropertyName("ClaimantIDColumn");

this.RuleFor(x => x.Cell("D"))
.Must(ExcelValidationHelpers.BeADate).WithMessage("InvoiceDate column value is not a valid date.")
.OverridePropertyName("InvoiceDateColumn");

this.RuleFor(x => x.Cell("F"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Fees column value is not a valid decimal.")
.OverridePropertyName("FeesColumn");

this.RuleFor(x => x.Cell("G"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Costs column value is not a valid decimal.")
.OverridePropertyName("CostsColumn");

this.RuleFor(x => x.Cell("H"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Adjustments column value is not a valid decimal.")
.OverridePropertyName("AdjustmentsColumn");

this.RuleFor(x => x.Cell("I"))
.Must(ExcelValidationHelpers.BeADecimal).WithMessage("Total column value is not a valid decimal.")
.OverridePropertyName("TotalColumn");
}


}
```


My Excel Validation helpers are as follows:
```C#
public static bool BeADecimal(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<decimal>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

public static bool BeADate(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<DateTime>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

public static bool BeALong(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<long>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

public static bool BeAnInt(IXLCell cellToCheck)
{
try
{
// ReSharper disable UnusedVariable -- this is OK; the value will never be used in this case but needs to be assigned.
var test = cellToCheck.GetValue<int>();
// ReSharper restore UnusedVariable
return true;
}
catch (Exception)
{
return false;
}
}

}
```

##I know it's a lot -- please ask questions!

The complicated nature of the code means it's tough for me to succinctly show the problem, especially since it involves an exception that I can't (yet) trap or trace in any way. I will do my best to rip this code out and get it into an exe of some kind that can be studied. I am happy to answer any questions you may have.

Updated Wiki: Home

$
0
0

Project Description

ClosedXML makes it easier for developers to create Excel 2007/2010 files. It provides a nice object oriented way to manipulate the files (similar to VBA) without dealing with the hassles of XML Documents. It can be used by any .NET language like C# and Visual Basic (VB).

Q: Dude, where have you been?

A: I've been making a survey app called Conspek. It's now open to the public. My hope is that it will be able to pay the bills and allow me to keep working on ClosedXML.

Q: Why a survey tool?

A: The same reason I created ClosedXML, I wasn't happy with my options. A while back I had to create a survey but all online survey apps were fiendishly hard, all so clunky, and with a million options in my face (that I would never use). So I created my own survey tool with the goal of making the experience as easy and simple as possible. Try it out and give me some feedback at Conspek.com ^_^


What can you do with this?

ClosedXML allows you to create Excel 2007/2010 files without the Excel application. The typical example is creating Excel reports on a web server.

If you've ever used the Microsoft Open XML Format SDK you know just how much code you have to write to get the same results as the following 4 lines of code.

            var workbook = new XLWorkbook();
            var worksheet = workbook.Worksheets.Add("Sample Sheet");
            worksheet.Cell("A1").Value = "Hello World!";
            workbook.SaveAs("HelloWorld.xlsx");



Something more elaborate:

The Documentation page has an example of how to create the following table (Showcase) as well as many other examples:

Showcase.jpg

 

Created Unassigned: workbook.SaveAs hangs for ever [9263]

$
0
0
Hi, I am creating simple xlsx using template and then saving it this way :
> workbook.SaveAs(outputPath);

the problem is , that when I open my website in 3 tabs, and click in each to generate my report, then when code comes to SaveAs all tabs are hanging for ever,
closedxml i saving for ever, i was waiting 30 minutes and nothing, all is on my local machine, what I can do ? How can I check anything ?

New Post: NamedRange

$
0
0
Hi,

I am trying to copy a worksheet from one workbook to another. But it is not copying the named ranged to new sheet (IXLNamedRange)

I have tried using the below code, but showing error for some ranges

foreach (IXLNamedRange namedRange in srcBook.NamedRanges) {
foreach (IXLRange range in namedRange.Ranges) {
  destBook.NamedRanges.Add(namedRange.Name, range);
}
}

I am getting the error as "Sequence contains no matching element".

Thanks in advance.

Created Unassigned: InvalidOperationException when loading an Excel sheet with a funky comment. [9267]

$
0
0
See attached Excel sheet. When loading this sheet with ClosedXML, I receive the following error:

InvalidOperationException: Sequence contains no matching element

at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
at ClosedXML.Excel.XLWorkbook.LoadSpreadsheetDocument(SpreadsheetDocument dSpreadsheet) in d:\Temp\closedxml-80652\ClosedXML\ClosedXML\ClosedXML\Excel\XLWorkbook_Load.cs:line 334
at ClosedXML.Excel.XLWorkbook.LoadSheets(String fileName) in d:\Temp\closedxml-80652\ClosedXML\ClosedXML\ClosedXML\Excel\XLWorkbook_Load.cs:line 47
at ClosedXML.Excel.XLWorkbook.Load(String file) in d:\Temp\closedxml-80652\ClosedXML\ClosedXML\ClosedXML\Excel\XLWorkbook_Load.cs:line 36
at ClosedXML.Excel.XLWorkbook..ctor(String file, XLEventTracking eventTracking) in d:\Temp\closedxml-80652\ClosedXML\ClosedXML\ClosedXML\Excel\XLWorkbook.cs:line 626
at ClosedXML.Excel.XLWorkbook..ctor(String file) in d:\Temp\closedxml-80652\ClosedXML\ClosedXML\ClosedXML\Excel\XLWorkbook.cs:line 615
at ClosedXML_Sandbox.Program.Main(String[] args) in d:\Temp\closedxml-80652\ClosedXML\ClosedXML\ClosedXML_Sandbox\Program.cs:line 15
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

The error is located in this piece of code which handles comments:

```
var xml = xdoc.Root.Element("xml");
XElement shape;
if (xml != null)
shape = xml.Elements().First(e => (string)e.Attribute("type") == "#_x0000_t202");
else
shape = xdoc.Root.Elements().First(e => (string)e.Attribute("type") == "#_x0000_t202");
```
Somehow in our excel sheet, the comment has shape type #_x0000_t75. Which is also defined in the xdoc.

I quick fixed it for our situation by using FirstOrDefault and then checking if shape == null before continuing. But I think this could be handled more elegantly (since with my solution editing of the comment is not possible anymore).

New Post: Password protected workbook

$
0
0
Hi All,

Is there an example of how to create a password-protected workbook (so the password required to open the workbook)

Thanks
Michael

Source code checked in, #80736

New Post: Slow performance with range copy

$
0
0
Hi!

I try to produce print form in Excel. My approach is that before filling data, I try copy first page (like template) several times. And this copying extremly slow.
            for (int i = 1; i < subscriptionsByPages.Count(); i++) {
                ws.Cell("A" + (i * verticalPageSize + 1)).Value = ws.Range("A1:AB45");
            }
This code take about 95% of time and take about 5 minutes for 35-40 print page (1600-1800 rows on the sheet). I profile code and my result is:
set_Value - 95.5%
SetRange - 95.5%
[mscorlib.ni.dll] - 95.4%
Merge - 95.4%
Merge - 95.2%
Intersect - 94.7%
Dispose - 79.5% (another - Range 14.7%)
remove_RangeShiftedRows - 40.3% and removeRangeShiftedColumns - 39.1%

I use version 0.69.1.0.

What can I do for improving perfomance? May be it is wrong approach - to copy by range? Or I incorrect set value? Any suggestions, advices?

Commented Unassigned: IXCell.DataType isn't set DateTime type when the cell contains VLOOKUP formula [8939]

$
0
0
Hi there!

First, thank you for your hard work and ongoing support!

My issue is the following. Into a worksheet, a column has VLOOKUP formula to obtain a date from another sheet in the same workbook. But when checking the IXCell.DataType property, I get the Text data type instead of Date data type.

I'm using ClosedXML 0.68.1

I attach the sample project containing a excel sample file.

Thanks in advanced.
Comments: ** Comment from web user: soyalfonsillo **

Thanks for this useful project.

A question about this. So, how I can test if cell is formatted as date?

Thanks in advance,

Alfonso

Created Unassigned: WorkSheet CopyTo doesn't transform Named Ranges addresses [9270]

$
0
0
I'm trying to replicate a Worksheet several time in a Workbook and I'm doing using the following code:
```
IXLWorksheet worksheet = modelSheet.CopyTo("SheetName");
```
When I open the generated document the NamedRanges were copied, using the same name as expected, but all of them are associated to the model worksheet (source). I was expecting the NamedRange address to be changed to the target Worksheet too.

Example:
```
"=ModelSheet!$B$10:$B$10" would transform to "=TargetSheet!$B$10:$B$10"
```

Is there a way to do it or isn't it supported yet?

Many Thanks & great work my man, incredible Lib!
Cheers!

Commented Unassigned: system.memoryout of exception [9259]

$
0
0
Hi

I exporting around 50,000 rows to excel. I am using row grouping. I have lot of groupings. It works well for 20k rows but memory spikes a lot to atleast 1 gb. Its happening on the windows 2008 r2 servers with 24 gb ram

My data is lot of processed data before passing it to worksheet. This is the reason i am unable to provide data. Please let me know if there are any corrections i need to make to get it work

Thanks

using (var workbook = new ClosedXML.Excel.XLWorkbook())
{
var ws = workbook.Worksheets.Add(dt);
if (indentLevel == 2)
{

ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Red;
}
else if (indentLevel == 3)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Blue;
}
else if (indentLevel == 4)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.ShockingPink;
}
else if (indentLevel == 5)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Green;
}
else if (indentLevel == 6)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Maroon;
}
else if (indentLevel == 7)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Purple;
}
else if (indentLevel == 8)
{
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Group();
ws.Rows(pointer_string.ToString() + ":" + moving_string.ToString()).Style.Font.FontColor = XLColor.Orange;
}
}
catch (Exception ex)
{
string script = "<script type=\"text/javascript\">alert('No results to export to excel');</script>";
ClientScript.RegisterClientScriptBlock(this.GetType(), "Alert", script);
break;
}
}

for (int i = 0; i < dt.Rows.Count; i++)
{
ws.Cell(i + 2, 17).Style.Font.FontColor = XLColor.Blue;
ws.Cell(i + 2, 17).Style.Font.Underline = XLFontUnderlineValues.Single;
ws.Cell(i + 2, 17).Hyperlink = new XLHyperlink(ConfigurationSettings.AppSettings["url"].ToString() + "displaybss.aspx?partnumber=" + dt.Rows[i]["Prt No"].ToString() + "&partrev=" + dt.Rows[i]["Rev"].ToString());
}

//ws.Columns().AdjustToContents();
ws.Columns(maxlevel + 1, 15).Hide();
ws.Outline.SummaryHLocation = XLOutlineSummaryHLocation.Left;
ws.Outline.SummaryVLocation = XLOutlineSummaryVLocation.Top;


HttpResponse response = Response;
response.Clear();
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
response.AddHeader("content-disposition", "attachment;filename=Results.xlsx");

//MemoryStream MyMemoryStream = new MemoryStream();
using (MemoryStream MyMemoryStream = new MemoryStream())
{

workbook.SaveAs(MyMemoryStream);
response.Charset = "";
response.AddHeader("Content-Length", MyMemoryStream.Length.ToString());
response.BinaryWrite(MyMemoryStream.GetBuffer());
}

response.Flush();
response.OutputStream.Close();
response.End();
workbook.Dispose();
ws.Dispose();
ws = null;
GC.Collect();
GC.SuppressFinalize(workbook);
HttpContext.Current.ApplicationInstance.CompleteRequest();
}

}
Comments: ** Comment from web user: duncans **

Don't save the workbook to a MemoryStream because this - as the name suggests - loads the entire thing into memory, which is one of the things causing your OutOfMemoryException.

I suggest saving it to a temporary file on the file system then use Response.TransmitFile to send it. You will need to have some housekeeping task to tidy up the temporary files.

Created Unassigned: Named ranges and apostrophes [9272]

$
0
0
I noticed the following behavior regarding apostrophes in Office Excel.
When I manually add a named range with worksheet scope to a sheet with a name containing an apostrophe, e.g. "C 09.02(LAO PEOPLE'S DEMOCRATI)"
the named range is created like this:

Scope: "C 09.02(LAO PEOPLE'S DEMOCRA)"
Refers to: "='C 09.02(LAO PEOPLE''S DEMOCRATI)'!$D$8"

Excel is adding an additional apostrophe in the "Refers to:" field. NOTE: Two apostrophes in PEOPLE''S

ClosedXML doesn’t seem to behave in a similar manner when adding named ranges in this particular case.
When I try to open the Excel file I get a message saying that it is a problem with the document and the named ranges are removed.

I have made a workaround in a private fork of ClosedXML to deal with this issue.

In the class XLRangeAddress I have changed
Worksheet.Name
to
Worksheet.Name.Replace("'","''")

Like this:

```
public String ToStringFixed(XLReferenceStyle referenceStyle, Boolean includeSheet)
{
if (includeSheet)
return String.Format("'{0}'!{1}:{2}",
Worksheet.Name.Replace("'","''"),
_firstAddress.ToStringFixed(referenceStyle),
_lastAddress.ToStringFixed(referenceStyle));

return _firstAddress.ToStringFixed(referenceStyle) + ":" + _lastAddress.ToStringFixed(referenceStyle);
}
```

Edited Issue: Creating a new macro-enabled Excel spreadsheet does not work [9245]

$
0
0
I need to create a new XSLM spreadsheet document.

I am using this code. The resulting file cannot be opened by Excel 2010 and it is actually an XLSX file. I am able to open when I change its extension to XLSX.

```
var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell("A1").Value = "Hello World!";
workbook.SaveAs("HelloWorld.xlsm");
```

New Post: "unreadable content" error when opening Excel file created via ClosedXML

$
0
0
You may need to set the cells DataType. This is the only thing that worked in my case.

ex..

ApprovedCoursesSheet.Cell(Row, 1).DataType = XLCellValues.Text
ApprovedCoursesSheet.Cell(Row, 1).SetValue(Of Int32)(c.APPL_COURSE_ID)
ApprovedCoursesSheet.Cell(Row, 2).DataType = XLCellValues.Text
ApprovedCoursesSheet.Cell(Row, 2).SetValue(Of String)(c.APPL_COURSE_NAME)

New Post: Changing table column header texts

$
0
0
Hello,

thanks for the effort you've put into ClosedXML.

However, I'm struggling with tables on sheets. In the code (please see below, VS2012, .NET 4.0, ClosedXML 0.69.1.0) I load an XLSX file which only contains a table with headers on a sheet. If I then change a column header text via the cell's Value property or SetValue method, Excel 2013 complains about invalid data in the saved XLSX file when opening it. What is the suggested way to change a table column's header text? Does it matter whether the table's header cell is accessed via the worksheet's Cell(...) method or via the table object's Cell(...) method?
I tried the example from https://closedxml.codeplex.com/discussions/406341 and it does work but unfortunately there's a template XLSX file with an existing table I need to alter and populate with data. I also tried to change the header text using the output file of the linked example as template. The Open XML 2.0 SDK Productivity Tools validation only points out four invalid margins in the XLSX file. A diff on both XLSX file contents does not reveal anything unexpected.

Any help is appreciated. Thanks a lot in advance!

Kind regards,
Kristian


Code excerpt:
using (XLWorkbook workbook = new XLWorkbook(@"template.xlsx"))
{
    // Access sheet and table by indices because this example only contains one sheet and one table.
    IXLWorksheet sheet = workbook.Worksheet(1);
    IXLTable table = sheet.Table(0);
    workbook.SaveAs(@"resultOriginal.xlsx");
    // Change first column header text.
    table.Cell(1, 1).Value = "Name";
    workbook.SaveAs(@"result.xlsx");
}
Viewing all 1877 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>