I have two different fonts defined in the style sheet but If I use the second style with StyleIndex=1 . I am unable to open the generated spread sheet. Any help would be greatly appreciated
My code
Private Function GenerateStyleSheet() As Stylesheet
Dim ss As Stylesheet = New Stylesheet()
Dim fonts1 As Fonts = New Fonts()
Dim f1 As Font = New Font()
Dim f1Size As FontSize = New FontSize()
f1Size.Val = 11D
f1.Append(f1Size)
Dim f2 As Font = New Font()
Dim b2 As Bold = New Bold()
Dim f2Size As FontSize = New FontSize()
f2Size.Val = 11D
f2.Append(b2)
f2.Append(f2Size)
fonts1.Append(f1)
fonts1.Append(f2)
fonts1.Count = fonts1.ChildElements.Count
ss.Append(fonts1)
Return ss
End Function
Function getBoldTextCell(ByVal cell As String, ByRef row As Row, ByVal val As String) As Row
Dim refCell As Cell = Nothing
Dim newCell As New Cell()
newCell.StyleIndex = 1 // 0 works
newCell.CellReference = cell
row.InsertBefore(newCell, refCell)
newCell.CellValue = New CellValue(val)
newCell.DataType = New EnumValue(Of CellValues)(CellValues.String)
Return (row)
End Function
XML Code:
<x:row xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:c r="A1" s="0" t="str">
<x:v>Request #</x:v>
</x:c>
<x:c r="B1" t="str">
<x:v>1</x:v>
</x:c>
</x:row>
Style Code:
<x:fonts count="2" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:font>
<x:sz val="11" />
</x:font>
<x:font>
<x:b />
<x:sz val="11" />
</x:font>
</x:fonts>
You cannot define styles like that . You need to create a Style with Fonts , Fills , Borders and create cellformats from defined Fonts , Fills , Borders as given below.
// <Fonts>
Font font0 = new Font(); // Default font
Font font1 = new Font(); // Bold font
Bold bold = new Bold();
font1.Append(bold);
Fonts fonts = new Fonts(); // <APENDING Fonts>
fonts.Append(font0);
fonts.Append(font1);
// <Fills>
Fill fill0 = new Fill(); // Default fill
Fills fills = new Fills(); // <APENDING Fills>
fills.Append(fill0);
// <Borders>
Border border0 = new Border(); // Defualt border
Borders borders = new Borders(); // <APENDING Borders>
borders.Append(border0);
// <CellFormats>
CellFormat cellformat0 = new CellFormat() { FormatId = 0, FillId = 0, BorderId = 0 };
CellFormat cellformat1 = new CellFormat(new Alignment() { Horizontal HorizontalAlignmentValues.Center, Vertical = VerticalAlignmentValues.Center }) { FontId = 1 };
// <APENDING CellFormats>
CellFormats cellformats = new CellFormats();
cellformats.Append(cellformat0);
cellformats.Append(cellformat1);
// Append FONTS, FILLS , BORDERS & CellFormats to stylesheet <Preserve the ORDER>
workbookstylesheet.Append(fonts);
workbookstylesheet.Append(fills);
workbookstylesheet.Append(borders);
workbookstylesheet.Append(cellformats);
And later when defining cells , add style refference as
cell.StyleIndex=0 ; // Default style
cell1.StyleIndex=1 ; // Our defined style 1
Related
I'm creating an Excel file by x++, in Dynamics 365 - D365, I would like to add the background color by X++.
I'm using this code
System.IO.Stream workbookStream = new System.IO.MemoryStream();
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
var package = new OfficeOpenXml.ExcelPackage(memoryStream)
var package = new OfficeOpenXml.ExcelPackage(memoryStream)
var worksheets = package.get_Workbook().get_Worksheets();
var worksheet = worksheets.Add("SHEET");
var cells = worksheet.get_Cells();
var currentRow=1 ;
var cell = cells.get_Item(currentRow,1);
cell.set_Value("__MY__Value");
// NOT Work - compile error
//cell.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color::FromArgb(190, 0, 0));
//cell.Style.Fill.BackgroundColor.Rgb(Winapi::rgb2int(255,255,255));
Both commented lines give a Invalid token '('. compiler error.
How can I use the Background color property about Excel cell, by X++ in right way?
Thanks in advance.
As is often the case when doing .Net Interop from x++, the compiler can be a bit difficult if you mix a chain of properties and method calls. It usually helps to put the last property of the chain into its own variable and then call the method on that variable.
So instead of writing
cell.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color::FromArgb(190, 0, 0));
write this instead:
ExcelColor backgroundColor = cell.Style.Fill.BackgroundColor;
backgroundColor.SetColor(System.Drawing.Color::FromArgb(190, 0, 0));
This will get rid of the Invalid token '('. error.
However, now a runtime exception System.ArgumentException: Can't set color when patterntype is not set. is thrown. This is because OpenOfficeXml expects a fill style along with a background color so that Excel knows how the background color should be applied to the background. See the GettingStartedSample.cs#L57-L64.
I wrote the following code as a runnable class example that produces an Excel file with two values with background colors.
using OfficeOpenXml;
using OfficeOpenXml.Style; // note the additional namespace
class SOCreateExcelWithBackgroundColor
{
public static void main(Args _args)
{
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
using (var package = new ExcelPackage(stream))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add('CellBackground');
// add some values and colors
ExcelRange cell = worksheet.Cells.get_Item('A1');
cell.Value = 'Value1';
ExcelFill fill = cell.Style.Fill;
fill.PatternType = ExcelFillStyle::Solid;
ExcelColor backgroundColor = fill.BackgroundColor;
backgroundColor.SetColor(System.Drawing.Color::FromArgb(0, 87, 183));
cell = worksheet.Cells.get_Item('A2');
cell.Value = 'Value2';
fill = cell.Style.Fill;
fill.PatternType = ExcelFillStyle::Solid;
backgroundColor = fill.BackgroundColor;
backgroundColor.SetColor(255, 255, 215, 0); // note that the first 255 defines the transparency (alpha value) of the color
package.Save();
}
File::SendFileToUser(stream, 'CellBackground.xlsx');
}
}
}
This creates the following Excel:
I've been following this guide https://msdn.microsoft.com/EN-US/library/office/cc861607.aspx to insert a string to a cell in an excel file. The example is really confusing, and even when i copy/paste it doesn't work. I'm looking for a very simple example to insert a a value into a cell like:
spredSheet.InsertCell("A", 1, string value)
I could really use a simple code example showing me how to insert data into a cell using OpenXML in asp.net.
I tried the code from this post Using OpenXML to insert a datatable into excel, but it creates a broken excel file.
This is how my code look without the helper functions from the link
using (SpreadsheetDocument myDoc = SpreadsheetDocument.
Create(Server.MapPath("/data.xls"), SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookpart = myDoc.AddWorkbookPart();
workbookpart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
//add column names to the first row
Row header = new Row();
header.RowIndex = (UInt32)1;
SheetData sheetData = new SheetData();
Cell headerCell = createTextCell(1, 1, text);
header.AppendChild(headerCell);
sheetData.AppendChild(header);
// Add a WorkbookPart to the document.
worksheetPart.Worksheet = new Worksheet(sheetData);
}
The MSDN example is using SpreadsheetDocument.Open which opens an existing file but you are creating a brand new file with SpreadsheetDocument.Create. When you create a brand new file there are certain elements you must create in order for the file to be valid. The elements you are missing are the Sheets and Sheet elements.
Sheets are stored separately from the SheetData so you need to create a Sheet inside a Sheets and then associate the Sheets with the WorksheetPart.
This can be done like so:
Sheets sheets = myDoc.WorkbookPart.Workbook.AppendChild(new Sheets());
sheets.AppendChild(new Sheet()
{
Id = myDoc.WorkbookPart.GetIdOfPart(myDoc.WorkbookPart.WorksheetParts.First()),
SheetId = 1,
Name = "Sheet1"
});
So your full code listing would be something like:
using (SpreadsheetDocument myDoc = SpreadsheetDocument.
Create(Server.MapPath("/data.xls"), SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookpart = myDoc.AddWorkbookPart();
workbookpart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
//add column names to the first row
Row header = new Row();
header.RowIndex = (UInt32)1;
SheetData sheetData = new SheetData();
Cell headerCell = createTextCell(1, 1, text);
header.AppendChild(headerCell);
sheetData.AppendChild(header);
// Add a WorkbookPart to the document.
worksheetPart.Worksheet = new Worksheet(sheetData);
//this is the part that was missing from your code
Sheets sheets = myDoc.WorkbookPart.Workbook.AppendChild(new Sheets());
sheets.AppendChild(new Sheet()
{
Id = myDoc.WorkbookPart.GetIdOfPart(myDoc.WorkbookPart.WorksheetParts.First()),
SheetId = 1,
Name = "Sheet1"
});
}
I have this code:
Document document = new Document();
Section sec = document.AddSection();
Paragraph par;
for (int i = 0; i < 50; i++)
{
par = sec.AddParagraph();
par.AddText("Wiki je označení webů (nebo obecněji hypertextových dokumentů), které umožňují uživatelům přidávat obsah podobně jako v internetových diskusích, ale navíc jim také umožňují měnit stávající obsah; v přeneseném smyslu se jako wiki označuje software, který takovéto weby vytváří.Původně se termín wiki používal zcela opačně. Wiki bylo označení typu softwaru a weby postavené.");
}
par = sec.Headers.Primary.AddParagraph();
par.AddText("hlavicka");
Borders hranice = new Borders();
hranice.Width = 1;
sec.Headers.Primary.Format.Borders = hranice;
sec.AddImage("images.jpg");
par = sec.AddParagraph();
par.AddText("paticka");
PdfDocumentRenderer print = new PdfDocumentRenderer(false, PdfFontEmbedding.Always);
print.Document = document;
print.RenderDocument();
print.PdfDocument.Save("ahoj.pdf");
I need to make a Footer only on the last page. Is it possible?
MemoryStream PdfDocumnet()
{
Document pdfdoc = new MigraDoc.DocumentObjectModel.Document();
pdfdoc.Info.Title = "Doc Title";
pdfdoc.Info.Subject = "Doc Subject";
DefineProformaStyles(pdfdoc);
CreatePdf(pdfdoc);
MemoryStream stream = new MemoryStream();
PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
renderer.Document = pdfdoc;
renderer.RenderDocument();
renderer.Save(stream, false);
return stream;
}
private void CreatePdf(Document pdfDoc)
{
pdfDoc.DefaultPageSetup.HeaderDistance = "0.8cm";
pdfDoc.DefaultPageSetup.FooterDistance = "0.6cm";
MigraDoc.DocumentObjectModel.Section section = pdfDoc.AddSection();
section.PageSetup.TopMargin = "6.8cm"; //Unit.FromCentimeter(3.0);
section.PageSetup.BottomMargin = "3.4cm"; //Unit.FromCentimeter(3.0);
// HEADER ///////////////////////////////////////////////////////////////////////////////////
MigraDoc.DocumentObjectModel.Tables.Table tableh1 = section.Headers.Primary.AddTable();
Column colh1 = tableh1.AddColumn("10.8cm");
Column colh2 = tableh1.AddColumn("8cm");
colh2.Format.Alignment = ParagraphAlignment.Right;
// ...
// ... add content to header
// ...
//FOOTER for every page //////////////////////////////////////////////////////////////////////
MigraDoc.DocumentObjectModel.Tables.Table tablef2 = section.Footers.Primary.AddTable();
tablef2.Style = "Table";
//add content to footer
// BODY ///////////////////////////////////////////////////////////////////////////////////
MigraDoc.DocumentObjectModel.Tables.Table tableC = section.AddTable();
TextFrame frm0 = section.AddTextFrame();
Paragraph prg1 = section.AddParagraph();
//....
//.....
//FOOTER FOR ONLY LAST PAGE //////////////////////////////////////////////////////////////////
//Add an empty paragraph. If there is not enough space to fit in current page then ... page break
Paragraph emptyPar = section.AddParagraph();
emptyPar.Format.SpaceBefore = "2.6cm";
//add the special footer
string lastPageFooterImgFile = HttpContext.Current.Server.MapPath("/company/CompanyFooter.png");
TextFrame lastframe = section.AddTextFrame();
lastframe.Height = "2.6cm";
lastframe.RelativeVertical = RelativeVertical.Page;
lastframe.Top = "24cm"; // 24cm + 2.6cm + footer_for_every_page.Height = Page.Height
lastframe.AddImage(lastPageFooterImgFile);
}
private void DefineProformaStyles(Document Doc)
{
Doc.DefaultPageSetup.LeftMargin = "1.3cm";
MigraDoc.DocumentObjectModel.Style style = Doc.Styles["Normal"];
style = Doc.Styles[StyleNames.Header];
style.ParagraphFormat.AddTabStop("1cm", TabAlignment.Right);
style = Doc.Styles[StyleNames.Footer];
style.ParagraphFormat.AddTabStop("1cm", TabAlignment.Center);
style = Doc.Styles.AddStyle("Table", "Normal");
style.Font.Name = "Times New Roman";
style.Font.Size = 9;
style = Doc.Styles.AddStyle("Reference", "Normal");
style.ParagraphFormat.SpaceBefore = "1mm";
style.ParagraphFormat.SpaceAfter = "1mm";
style.ParagraphFormat.TabStops.AddTabStop("1cm", TabAlignment.Right);
}
There is no way to create a real footer on the last page.
You can create a TextFrame with your last paragraph. TextFrames are Shapes and can be placed at an absolute position on the page, so you can also place them where the Footer would be.
For example:
You need a 30mm place over the footer on the last page. (That could be a signature field.)
Define the PageSetup without this place (only footer hight + your distance from the bottom of the page)
Define your 30mm paragraph or table as TextFrame on a fix position: TextFrame.RelativeVertical = RelativeVertical.Page; frame.Top = ShapePosition.Bottom;
Define an empty paragraph as the last paragraph of the document with paragraph.Format.SpaceBefore = 30mm
Now the 30mm empty paragraph is on the end of all Documents and the signature overlapped it or the place for signature is not enough. Then the 30mm empty place forces a page break.
I want to add the ability to generate a PDF of the content in my application (for simplicity, it will be text-only).
Is there any way to automatically work out how much content will fit in a single page, or to get any content that spills over one page to create a second (third, fourth, etc) page?
I can easily work it out for blocks of text - just split the text by a number of characters into a string array and then print each page in turn - but when the text has a lot of white space and character returns, this doesn't work.
Any advice?
Current code:
public void Generate(string title, string content, string filename)
{
PdfDocument document = new PdfDocument();
PdfPage page;
document.Info.Title = title;
XFont font = new XFont("Verdana", 10, XFontStyle.Regular);
List<String> splitText = new List<string>();
string textCopy = content;
int ptr = 0;
int maxCharacters = 3000;
while (textCopy.Length > 0)
{
//find a space in the text near the max character limit
int textLength = 0;
if (textCopy.Length > maxCharacters)
{
textLength = maxCharacters;
int spacePtr = textCopy.IndexOf(' ', textLength);
string startString = textCopy.Substring(ptr, spacePtr);
splitText.Add(startString);
int length = textCopy.Length - startString.Length;
textCopy = textCopy.Substring(spacePtr, length);
}
else
{
splitText.Add(textCopy);
textCopy = String.Empty;
}
}
foreach (string str in splitText)
{
page = document.AddPage();
// Get an XGraphics object for drawing
XGraphics gfx = XGraphics.FromPdfPage(page);
XTextFormatter tf = new XTextFormatter(gfx);
XRect rect = new XRect(40, 100, 500, 600);
gfx.DrawRectangle(XBrushes.Transparent, rect);
tf.DrawString(str, font, XBrushes.Black, rect, XStringFormats.TopLeft);
}
document.Save(filename);
}
You can download PDFsharp together with MigraDoc. MigraDoc will automatically add pages as needed, you just create a document and add your text as paragraphs.
See MigraDoc samples page:
http://pdfsharp.net/wiki/MigraDocSamples.ashx
MigraDoc is the recommended way.
If you want to stick to PDFsharp, you can use the XTextFormatter class (source included with PDFsharp) to create a new class that also supports page breaks (e.g. by returning the count of chars that fit on the current page and have the calling code create a new page and call the formatter again with the remaining text).
I have made a table with cells and interested in having an image in one of the cell.
Below is my code:
doc.Open();
PdfPTable table = new PdfPTable(2);
table.TotalWidth = 570f;
table.LockedWidth = true;
table.HorizontalAlignment = 1; //0=Left, 1=Centre, 2=Right
PdfPCell points = new PdfPCell(new Phrase("and is therefore entitled to 2 points", arialCertify));
points.Colspan = 2;
points.Border = 0;
points.PaddingTop = 40f;
points.HorizontalAlignment = 1;//0=Left, 1=Centre, 2=Right
table.AddCell(points);
// add a image
doc.Add(table);
Image jpg = Image.GetInstance(imagepath + "/logo.jpg");
doc.Add(jpg);
With the above code, the image shows in my pdf but I want it to be inside a cell so that I can add more cells to the right of the image.
On the very basic level you can simply add the image to a PdfPCell and add this cell to your table.
So using your code...
PdfPCell points = new PdfPCell(new Phrase("and is therefore entitled to 2 points", arialCertify));
points.Colspan = 2;
points.Border = 0;
points.PaddingTop = 40f;
points.HorizontalAlignment = 1;//0=Left, 1=Centre, 2=Right
// add a image
iTextSharp.text.Image jpg = iTextSharp.text.Image.GetInstance(imagepath + "/logo.jpg");
PdfPCell imageCell = new PdfPCell(jpg);
imageCell.Colspan = 2; // either 1 if you need to insert one cell
imageCell.Border = 0;
imageCell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.AddCell(points);
// add a image
table.AddCell(imageCell);
doc.Add(table);
Update
Check your imagepath. This should be an absolute path to the image, and not relative like in a website page. Also, change your `/logo.jpg' to '\logo.jpg'
this is assuming imagepath is actually to the directory, and not the actual image...
I.E
Server.MapPath(imagepath) + "\\logo.jpg"