I am working on a program that generates an output document in Excel xlsx format. I wrote the functionality and was getting the expected output/result using Excel Interop, originally, but it was taking quite awhile to complete a single output so I am trying to duplicate the same functionality using OpenXML (currently using the ClosedXML library to simplify the conversion from the Excel Interop but I'm open to any other libraries or methods...)
The basic process is opening the template file (which has the initial print area [A1:M27] and print settings are already set up and defined) and then populating the template with the data. The first row of data starts in cell A11 with additional rows are inserted below this, as needed. (There is additional stuff on the template that is below this table of data, so the last row that is inserted is not the bottom of the actual print area.)
After inserting the second row of data, I have a function that will check if the value of the given cell and the value of the cell located immediately above it are the same. If so, then it checks to make sure that there aren't any page breaks located there before merging them.
Here's that section of relevant code:
For Each HBreak In outputSheet.PageSetup.RowBreaks
If HBreak = FirstCell.CellAbove.WorksheetRow.RowNumber Then Exit Sub
Next HBreak
When I generate the output, however, it still ends up merging cells across page breaks. I stepped through the code and found that outputSheet.PageSetup.RowBreaks is always empty... yet when I open the output file in Excel, there will be an automatic page break going right through the middle of the cells it merged.
I did a test and inserted a horizontal page break right where the data rows are inserted into the template to see if it would correctly detect manually-placed page breaks and then the check for a page break worked as intended... but only for the manually inserted break.
So it seems my issue is with the page break locations that are determined automatically based on the existing printing and page setup.
Is it possible to determine where the automatic page breaks are with OpenXML (or anything other than Excel Interop)?
Any help or advice would be greatly appreciated.
Edit/Update:
I managed to come up with a way to work-around this for the current situation, but it doesn't work very well after inserting the first initial page break.
I took the template and incrementally increased the row height until I found the point where increasing any row heights by one additional point caused the automatic page-break to shift. I wrote a function that summed the row heights before that pagebreak, giving me a value of 943.
Then, before checking for any page breaks, I call this procedure:
Private Sub InsertPageBreaks(outputSheet As IXLWorksheet)
Dim TotalHeight As Double = 0
Dim PageBreakHeight As Double = 943.5 ' Worksheet/Page Layout-specific value
' Reset/clear all of the horizontal row breaks
outputSheet.PageSetup.RowBreaks.Clear()
For x = 1 To (outputSheet.LastRowUsed(True).RowNumber)
TotalHeight += outputSheet.Row(x).Height
If TotalHeight > PageBreakHeight Then
' If the total height exceeds the page break point, insert a new
' new page break at this point and then reset TotalHeight
outputSheet.PageSetup.AddHorizontalPageBreak(x - 1)
TotalHeight = 0
End If
Next x
End Sub
The downside is that I will need to use a variation of this procedure for each different output template I use because of the differences in page layouts, scaling, page orientation, etc., so it isn't a very practical solution beyond this one specific application. Additionally, there appears to be a bit of "drift" that occurs after the first page break is inserted, and the pagebreaks no longer fit where Excel's automatic pagebreaks are inserted by the third page.
So... still looking for a better solution.
Related
I am trying to refer to an existing end note in word from a table cell in the document thus (using netoffice):
row.Cells[2].Range.InsertCrossReference(WdReferenceType.wdRefTypeEndnote, WdReferenceKind.wdEndnoteNumberFormatted, 1);
However, this appears to put the reference at the beginning of the row, rather than at the end of the text at Cell[2]. In general, I haven't found much help on the web on how to programmatically add a cross-reference to footnotes and end notes. How can I get the reference to display properly?
The problem is that the target Range specified in your code snippet is the entire cell. You need to "collapse" the Range to be within the cell. (Think of the Range like a Selection. If you click at the edge of a cell, the entire cell is selected, including its structural elements. If you then press left-arrow, the selection is collapsed to a blinking I-beam.)
To go to the start of the cell:
Word.Range rngCell = row.Cells[2].Range;
rngCell.Collapse(Word.WdCollapseDirection.wdCollapseStart);
rngCell.InsertCrossReference(WdReferenceType.wdRefTypeEndnote, WdReferenceKind.wdEndnoteNumberFormatted, 1);
If the cell has content and you want it at the end of the content, then you use wdCollapseEnd instead. The tricky part about that is this puts the target point at the start of the next cell, so it has to be moved back one character:
Word.Range rngCell = row.Cells[2].Range;
rngCell.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
rng.MoveEnd(Word.WdUnits.wdCharacter, -1);
rngCell.InsertCrossReference(WdReferenceType.wdRefTypeEndnote, WdReferenceKind.wdEndnoteNumberFormatted, 1);
1)I am using matrix to show my data as tax for each year. So in row I am showing tax name and for column I am grouping against year. I using rdlc to export it as pdf. on a page as per width it showing 6 column and as there is no space it split remaining columns on another page. Now my issue is, there are no much rows and there is space on same page below that tablix to occupy another tablix (splitted column's) still it is moving remaining columns on another page. I tried with keepTogether property but is it not working for me. I set it for tablix,column group also.
2) Now I want to use this above report as sub report so I add this report on another report file at the end of page. So while rendering the report as subreport it split exceed columns on another page which is also at the end of page keeping a lot of empty space at start of that second page. How can I avoid this.
Suppose I have Main report with some basic info at first then I put sub report at end of first page. Now sub report contains data in matrix which column increases dynamically. so after 4 column it split and goes on next page for next page and put remaining columns on next page at the END. Which I want at the start of next page.
basic info
sub report content in matrix
---------------------------------------------------------------------------
page break here from sub report as more columns are there.
( this space remain blank. I want to avoid this blank space.)
sub report remaining columns came here.
I'm using MigraDoc to generate some PDFs. I have code to create a table of text for each element in an array and am printing out pages with these tables.
However, the requirements I am being given is that if I have 2 tables, and the 2nd table would not fit on the page due to the length of the first table, I need the 2nd table to start the next page. I then need to repeat this for each table I am adding to my document.
How would I go about doing this?
If all tables are small enough to fit a single page, then there is a simple solution: set the KeepWith property of the first row to row count minus one to keep the whole table on one page.
If tables do not always fit a single page: you could try a hack, e.g. setting KeepWith to 6 or 8 or 10 (depends on the height of your table rows). If the value is close to what fits on a single page (without going over), tables will start on a new page automatically.
Obviously this will work very good if table rows have a constant height; if tables rows have varying heights, this will not work reliably, but will still prevent tables that will only have one or two rows on the first page (this is not your requirement, but maybe the requirement can be discussed?).
The clean (but complicated) way to fulfill your requirements: get access to the internal GetRenderInfoFromPage method. You will have to start an incremental process:
1) render the document;
2) if you find a split table, insert a page break before that table and repeat from 1.
See also here:
http://forum.pdfsharp.net/viewtopic.php?p=1960#p1960
m trying to break one large Excel spreadsheet into several. I've made good progress, but I'm running into some problems. Specifically, the values that get copied over don't retain their format (for instance, 40322 instead of 5/24/2010 and -101 instead of (101.00) ). I've tried using the style (see below) but that doesn't even get me the font, let alone the number format. Any help or a poke in the right direction would be appreciated.
There are 2 loops, one for row, one for column.
destinationSheet.Cells[i, j].Style = sourceSheet.Cells[i, j].Style;
Instead of looping for each cell, you can copy/paste the entire range of cells using the pastespecial method.
http://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.namedrange.pastespecial(VS.80).aspx
I am using PDFsharp / MigraDoc to write tables and charts to PDF files. This worked great so far, however MigraDoc will always split my tables (vertically) when it should move the whole table to the next page in the document. How do I make sure the table will stay in one piece?
Table class of MigraDoc.DocumentObjectModel.Tables has a bool KeepTogether property however it seems to have no effect (either set to true or false).
Is there a way to do it manually? Is there any way to "measure" the distance from the end of the page and compare it to tables height? (Or any other way of knowing wether the table will be split or not)
Please note that I am using PDFsharp / MigraDoc for the first time. If there are any best practices I ought to know, please let me know. If there are some good examples out there (I saw those on PDFSharp's home page, but that's about it) I'd love to know about them!
You can set the KeepWith property of a Table Row to specify blocks that must be kept together.
If you know the table fits on one page, you can set the KeepWith property of the first row to (table.Rows.Count - 1) when the table is finished.