MigraDoc table formatting / cell indent - c#

I'm trying to create a table with MigraDoc. I want it to look like this:
This is how the table should look
Instead I'm only getting this:
This is the table I'm getting
The text is too near to the border. The indent is missing. I tried
table.Format.LeftIndent = 0.2;
and
table.Format.LeftIndent = "0,2cm";
to set the indent for all table cells. But it didn't work. How can an indent for all table cells be achieved?
This is my complete test method:
private Document debugMigraDocTable()
{
Document document = setupDocument();
Section sectionProtocolHeader = document.AddSection();
Paragraph measValueParagraph = sectionProtocolHeader.AddParagraph("Measurement");
Table table = sectionProtocolHeader.AddTable();
table.Format.LeftIndent = 0.8;
// Table header
Column column = table.AddColumn("1,2cm");
column = table.AddColumn("1,7cm");
column = table.AddColumn("1,7cm");
column = table.AddColumn("1,2cm");
column = table.AddColumn("1,7cm");
column = table.AddColumn("1,7cm");
Row row = table.AddRow();
row.HeadingFormat = true;
row.Format.Alignment = ParagraphAlignment.Center;
row.Format.Font.Bold = true;
row.Cells[0].AddParagraph("Key");
row.Cells[1].AddParagraph("Value 1");
row.Cells[2].AddParagraph("Value 2");
row.Cells[3].AddParagraph("Key");
row.Cells[4].AddParagraph("Value 1");
row.Cells[5].AddParagraph("Value 2");
// Table data
row = table.AddRow();
row.Cells[0].AddParagraph("1");
row.Cells[1].AddParagraph("1,13");
row.Cells[2].AddParagraph("");
row.Cells[3].AddParagraph("33");
row.Cells[4].AddParagraph("0,84");
row.Cells[5].AddParagraph("");
row = table.AddRow();
row.Cells[0].AddParagraph("2");
row.Cells[1].AddParagraph("1,19");
row.Cells[2].AddParagraph("");
row.Cells[3].AddParagraph("34");
row.Cells[4].AddParagraph("1,35");
row.Cells[5].AddParagraph("");
row = table.AddRow();
row.Cells[0].AddParagraph("3");
row.Cells[1].AddParagraph("1,01");
row.Cells[2].AddParagraph("");
row.Cells[3].AddParagraph("35");
row.Cells[4].AddParagraph("1,28");
row.Cells[5].AddParagraph("");
return document;
}
For preview and printing I render this to RTF:
Document document = debugMigraDocTable();
RtfDocumentRenderer rtfRenderer = new RtfDocumentRenderer();
string rtf = rtfRenderer.RenderToString(document, Path.GetTempPath());

Related

Closed XML can't change the font name and size of pivot table

I have created a pivot table using Closed XML. I want to change the font name and size of the pivot table (cells). When I try doing so, it changes the font name and size of the outer sheet (not of the cell content in pivot table). I also tried setting the font name of each cell but couldn't work. Below is the part of my code -
public void CreatePivotTable(List<EmployeeModel> employeeModels)
{
var workbook = new XLWorkbook();
var sheet = workbook.Worksheets.Add("SourceData");
var table = sheet.Cell(1, 1).InsertTable(employeeModels, "SourceData", true);
var sheetName = "PivotTable";
var ptSheet = workbook.Worksheets.Add(sheetName);
ptSheet.Style.Font.FontName = "Arial";
ptSheet.Style.Font.FontSize = 8;
var pt = ptSheet.PivotTables.Add(sheetName, ptSheet.Cell(5, 2), table.AsRange());
// pt.SetPreserveCellFormatting(false);
pt.RowLabels.Add("EmpId").Compact = true;
pt.RowLabels.Add("EmpName");
pt.ColumnLabels.Add("Description");
pt.ColumnLabels.Add("Department");
pt.Values.Add("HR", "Sum of HR");
pt.Values.Add("MT", "Sum of MT");
pt.SetShowGrandTotalsRows(false);
ptSheet.Cell(1, 3).Value = DateTime.Now.ToString();
ptSheet.Cell(2, 3).Style.Font.Bold = true;
ptSheet.Columns().Width = 11;
ptSheet.Columns("C").Width = 25;
ptSheet.Columns("A").Width = 1;
ptSheet.Columns("B").Width = 0;
ptSheet.Columns("1,2").Hide();
ptSheet.SheetView.FreezeColumns(4);
ptSheet.SheetView.FreezeRows(7);
ptSheet.Rows(1, 4).Hide();
ptSheet.Rows(4, 4).Unhide();
pt.Theme = XLPivotTableTheme.None;
pt.SetClassicPivotTableLayout(true);
//Print Options.
PrintOptionsForPivotTable(ptSheet);
workbook.SaveAs(#"C:\Users\prags\source\repos\WindowsFormsApp1\ClosedXmlPivotTable\pivot.xlsx");
}

Adding a list of tables in migradoc

I have DB table that looks like
id | Name | ImagePath
-------------------------
1 | aaa | xxx
2 | bbb | yyy
3 | ccc | zzz
For each row I want to create a table, so when i generate my pdf each row will look like this in the pdf
--------------------|-------------------
1 |
aaa |xxx (but the actual image)
--------------------|-------------------
--------------------|-------------------
2 |
bbb |yyy (but the actual image)
--------------------|-------------------
--------------------|-------------------
3 |
ccc |zzz (but the actual image)
--------------------|-------------------
The values are passed into a function with creates the table
public MigraDoc.DocumentObjectModel.Tables.Table createTable(List<string> listOfValues)
{
MigraDoc.DocumentObjectModel.Tables.Table table = new MigraDoc.DocumentObjectModel.Tables.Table();
//table = page.AddTable();
table.Style = "Table";
table.Borders.Color = Colors.Black;
table.Borders.Width = 0.25;
table.Borders.Left.Width = 0.5;
table.Borders.Right.Width = 0.5;
table.Rows.LeftIndent = 0;
//create column
MigraDoc.DocumentObjectModel.Tables.Column column = new MigraDoc.DocumentObjectModel.Tables.Column();
column = table.AddColumn("10cm");
column.Format.Alignment = ParagraphAlignment.Left;
//MigraDoc.DocumentObjectModel.Tables.Row tableRow = table.AddRow();
MigraDoc.DocumentObjectModel.Tables.Column ImageColumn = new MigraDoc.DocumentObjectModel.Tables.Column();
ImageColumn = table.AddColumn("10cm");
ImageColumn.Format.Alignment = ParagraphAlignment.Left;
//create rows from list of values
foreach (var value in listOfValues)
{
MigraDoc.DocumentObjectModel.Tables.Row tableRow = table.AddRow();
//if it is an image add to column 2
if (value.Contains("Image="))
{
tableRow.Cells[1].AddParagraph(value);
//merge the cells for the image column (zero based)
tableRow.Cells[1].MergeDown = listOfValues.Count - 1;
}
else
{
//add the value
tableRow.Cells[0].AddParagraph(value);
}
}
return table
}
The above created a table and then returns it, which is put into a list (of type Table)
The list of tables is then passed into a method that generates the pdf.
public void generatePDF(List<MigraDoc.DocumentObjectModel.Tables.Table> listOfTables)
{
//who generated teh report
string author = Environment.UserName;
DateTime currentTime = DateTime.Now;
Document document = new Document();
string pageHeaderText = "Report";
string pageFooterText = string.Format("Report Generated by {0} at {1} on {2}", author, currentTime.ToShortTimeString(), currentTime.ToShortDateString());
Style style = document.Styles["Normal"];
style.Font.Name = "Arial Unicode MS";
//table Style
style = document.Styles.AddStyle("Table", "Normal");
style.Font.Name = "Verdana";
style.Font.Size = 9;
Section page = document.AddSection();
//header
Paragraph header = page.Headers.Primary.AddParagraph();
header.AddText(pageHeaderText);
header.Format.Alignment = ParagraphAlignment.Center;
//footer
Paragraph footer = page.Footers.Primary.AddParagraph();
footer.AddText(pageFooterText);
footer.Format.Alignment = ParagraphAlignment.Center;
//Main paragraph
Paragraph mainPara = page.AddParagraph("test\n");
//go through each table in the list and add to teh page
foreach (var table in listOfTables)
{
MigraDoc.DocumentObjectModel.Tables.Table tableToAdd = new MigraDoc.DocumentObjectModel.Tables.Table();
tableToAdd = table;
tableToAdd = page.AddTable();
}
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(true);//false, pdfRenderer.);
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
//save and open the file
fileName = "test;
//show file save dialog
SaveFileDialog sfd = new SaveFileDialog();
sfd.DefaultExt = ".pdf";
sfd.AddExtension = true;
sfd.FileName = fileName;
if (sfd.ShowDialog() == DialogResult.OK)
{
savePath = System.IO.Path.GetDirectoryName(sfd.FileName);
pdfRenderer.PdfDocument.Save(savePath + "\\" + fileName + ".pdf" );
Process.Start(savePath + "\\" + fileName + ".pdf");
}
}
The problem that I am having is that the table does not get generated on the pdf.
If i pass in a list of strings rather than the list of tables and loop through, the table does get generated, but I am unsure why when using the list (of type tables) does not get generated when looping through.
Computers often do what you tell 'em to do, not what you want 'em to do.
Look at this piece of code:
tableToAdd = table;
tableToAdd = page.AddTable();
You add a new, empty table to the page and assign the new table to the variable tableToAdd, thus losing the reference to the table with the contents.
The code that does what you expect is even simpler:
page.Add(tableToAdd);
It adds the table with the contents to the section.
BTW: page is not the best name for a Section object.

C# datagridviewbuttoncolumn no text showing

I need to show some texts on the DataGridViewButtonColumn. I've read lots of similar question about these on SO. Many of them answers recommend setting UseColumnTextForButtonValueto True which doesn't for me. It seems in an odd way that Microsoft makes it to have at least a row so that the button will display the text.
The following is my code:
DataGridViewButtonColumn EditColumn = new DataGridViewButtonColumn();
EditColumn.HeaderText = "Complete";
EditColumn.Name = "Complete";
EditColumn.UseColumnTextForButtonValue = True;
dataGridView.Columns.Add(EditColumn);
This code doesn not show the text on the DataGridViewButtonColumn:
The code that works here:
dataGridView1.ColumnCount = 2;
dataGridView1.Columns[0].Name = "a";
dataGridView1.Columns[1].Name = "b";
ArrayList row = new ArrayList();
row.Add("1");
row.Add("2");
dataGridView1.Rows.Add(row.ToArray());
DataGridViewButtonColumn btn = new DataGridViewButtonColumn();
btn.Name = "text";
btn.UseColumnTextForButtonValue = true;
dataGridView1.Columns.Add(btn);
This code works but however I am getting my data from a database and thus I won't be using dataGridView.Rows.Add(row.ToArray()) here. So how do I get the text to show on the DataGridViewButtonColumn ?
You have two problems to solve:
How bind a Button column to a DataSource
How to make the DataSource create not only default column types but also one (or more) button column
The first issue is basically solved by setting the DataPropertyName of the column.
But I do not know how or even if it is possible to influence the ColumnTypes created automatically.
Therefore I suggest a workaround: Instead of relying on the AutoGenerateColumns we can do it ourselves in a little helper function:
This clears the columns and creates a new one for each column in a DataTable, using the properties of the columns in the table. To tell it which column(s) we want to be buttons we pass a string with the column names, surrounded by spaces:
void CreateSpecialColumns(DataTable dt, DataGridView dgv, string buttons)
{
dgv.Columns.Clear();
for (int i = 0; i < dt.Columns.Count; i++ )
{
DataColumn dc = dt.Columns[i];
if (buttons.Contains(" " + dc.ColumnName + " "))
{
DataGridViewButtonColumn buttonColumn = new DataGridViewButtonColumn();
buttonColumn.HeaderText = dc.Caption;
buttonColumn.Name = dc.ColumnName;
buttonColumn.ValueType = dc.DataType;
buttonColumn.DataPropertyName = dc.ColumnName;
dgv.Columns.Add(buttonColumn);
}
else
{ // normal columns
int c = dgv.Columns.Add(dc.ColumnName, dc.Caption);
dgv.Columns[c].ValueType = dc.DataType;
dgv.Columns[c].DataPropertyName = dc.ColumnName;
}
}
}
Here is how I called it using a DataTable DT:
dataGridView1.AutoGenerateColumns = false;
CreateSpecialColumns(DT, dataGridView1, " Cook Waiter ", "");
dataGridView1.DataSource = DT;
Note that this only works if the UseColumnTextForButtonValue property is not set to true!
You need to set the Text property,
DataGridViewButtonColumn EditColumn = new DataGridViewButtonColumn();
EditColumn.HeaderText = "Complete";
EditColumn.Name = "Complete";
EditColumn.UseColumnTextForButtonValue = True;
EditColumn.Text = "Complete"; // --Text property added
dataGridView.Columns.Add(EditColumn);

Kendo Grid print all data to excel, not just visible data

Let´s say I have grid with 80 items and pagesize is 10, when printing from the controller I want to print all the data, not just the visible data on the first page.
I have good "Export Grid to Excel" test project from Telerik, and I´ve got the export feature all covered and working like a charm. Basically just including the NPOI file and start using it.
Is there a way for me to iterate all the product-data from the DataSourceRequest?
My code sample:
public FileResult Export([DataSourceRequest]DataSourceRequest request)
{
//Get the data representing the current grid state - page, sort and filter
IEnumerable products = db.Products.ToDataSourceResult(request).Data;
//TODO: Get all data but not just the data from the visible page as above!!!
//Create new Excel workbook
var workbook = new HSSFWorkbook();
//Create new Excel sheet
var sheet = workbook.CreateSheet();
//(Optional) set the width of the columns
sheet.SetColumnWidth(0, 10 * 256);
sheet.SetColumnWidth(1, 50 * 256);
sheet.SetColumnWidth(2, 50 * 256);
sheet.SetColumnWidth(3, 50 * 256);
//Create a header row
var headerRow = sheet.CreateRow(0);
//Set the column names in the header row
headerRow.CreateCell(0).SetCellValue("Product ID");
headerRow.CreateCell(1).SetCellValue("Product Name");
headerRow.CreateCell(2).SetCellValue("Unit Price");
headerRow.CreateCell(3).SetCellValue("Quantity Per Unit");
//(Optional) freeze the header row so it is not scrolled
sheet.CreateFreezePane(0, 1, 0, 1);
int rowNumber = 1;
//Populate the sheet with values from the grid data
foreach (Product product in products)
{
//Create a new row
var row = sheet.CreateRow(rowNumber++);
//Set values for the cells
row.CreateCell(0).SetCellValue(product.ProductID);
row.CreateCell(1).SetCellValue(product.ProductName);
row.CreateCell(2).SetCellValue(product.UnitPrice.ToString());
row.CreateCell(3).SetCellValue(product.QuantityPerUnit.ToString());
}
//Write the workbook to a memory stream
MemoryStream output = new MemoryStream();
workbook.Write(output);
//Return the result to the end user
return File(output.ToArray(), //The binary data of the XLS file
"application/vnd.ms-excel", //MIME type of Excel files
"GridExcelExport.xls"); //Suggested file name in the "Save as" dialog which will be displayed to the end user
}
The source from the DataSourceRequest class can be found here.
Probably if you disable the paging properties, you'll get all filtered + sorted data:
public FileResult Export([DataSourceRequest]DataSourceRequest request)
{
request.Take = 9999999;
request.Skip = 0;
// Get the data representing the current grid state : sort and filter
IEnumerable products = db.Products.ToDataSourceResult(request).Data;
After some time I stumbled upon an answer that works. #Stef answer got me on the right track although I didn´t actually use his answer, I will therefore up his answer for the help. I found a way to count the number of pages, and then simply edited the DataSourceRequest for each page. This way ensures me all the pages from the database. I hope this helps others in the future :)
public FileResult Export([DataSourceRequest]DataSourceRequest request)
{
//Count pages to use as iterator when adding to list
var pages = db.Products.ToDataSourceResult(request).Total/request.PageSize;
//Get the data representing the current grid state - page, sort and filter
//IEnumerable products = db.Products.ToDataSourceResult(request).Data;
//Get the data representing the current grid state - page, sort and filter
var products = new List<Product>();
//To ensure all pages get fetched from db
for (int i = 1; i < pages + 1; i++)
{
request.Page = i;
IEnumerable prod = db.Products.ToDataSourceResult(request).Data;
products.AddRange(prod.Cast<Product>().ToList());
}
//Create new Excel workbook
var workbook = new HSSFWorkbook();
//Create new Excel sheet
var sheet = workbook.CreateSheet();
//(Optional) set the width of the columns
sheet.SetColumnWidth(0, 10 * 256);
sheet.SetColumnWidth(1, 50 * 256);
sheet.SetColumnWidth(2, 50 * 256);
sheet.SetColumnWidth(3, 50 * 256);
//Create a header row
var headerRow = sheet.CreateRow(0);
//Set the column names in the header row
headerRow.CreateCell(0).SetCellValue("Product ID");
headerRow.CreateCell(1).SetCellValue("Product Name");
headerRow.CreateCell(2).SetCellValue("Unit Price");
headerRow.CreateCell(3).SetCellValue("Quantity Per Unit");
//(Optional) freeze the header row so it is not scrolled
sheet.CreateFreezePane(0, 1, 0, 1);
int rowNumber = 1;
//Populate the sheet with values from the grid data
foreach (Product product in products)
{
//Create a new row
var row = sheet.CreateRow(rowNumber++);
//Set values for the cells
row.CreateCell(0).SetCellValue(product.ProductID);
row.CreateCell(1).SetCellValue(product.ProductName);
row.CreateCell(2).SetCellValue(product.UnitPrice.ToString());
row.CreateCell(3).SetCellValue(product.QuantityPerUnit.ToString());
}
//Write the workbook to a memory stream
MemoryStream output = new MemoryStream();
workbook.Write(output);
//Return the result to the end user
return File(output.ToArray(), //The binary data of the XLS file
"application/vnd.ms-excel", //MIME type of Excel files
"GridExcelExport.xls"); //Suggested file name in the "Save as" dialog which will be displayed to the end user
}
you may use javascript to print all data to excel, like below
function ExportToCSV() {
var dataSource = $("#grid").data("kendoGrid").dataSource;
var filteredDataSource = new kendo.data.DataSource({
data: dataSource.data(),
filter: dataSource.filter()
});
filteredDataSource.read();
var data = filteredDataSource.view();
var result = "data:application/vnd.ms-excel,";
result += "<table><tr><th>ProductID</th><th>ProductName</th><th>UnitPrice</th><th>Discontinued</th><th>UnitsInStock</th><th>Category</th></tr>";
for (var i = 0; i < data.length; i++) {
result += "<tr>";
result += "<td>";
result += data[i].ProductID;
result += "</td>";
result += "<td>";
result += data[i].ProductName;
result += "</td>";
..
result += "</tr>";
}
result += "</table>";
if (window.navigator.msSaveBlob) {
window.navigator.msSaveBlob(new Blob([result]), 'export.xls');
} else {
window.open(result);
}
e.preventDefault();
}
hope this may help

DataTable in FlowDocument

I am trying to create a flowdocument with a Table of data which I want to print on the printer. I can create the flowdocument and the printer stuff, but I don't know how to create the table.
Here is my code:
//Creating flow document
Paragraph myParagraph = new Paragraph();
//Add content to the paragraph
myParagraph.Inlines.Add(new Bold(new Run("List of tasks (" + TasksToShow.Count + ")")));
//Create content of paragraph
DataTable myTable = new DataTable();
myTable.Columns.Add("Task ID", typeof(int));
myTable.Columns.Add("Task name", typeof(string));
foreach (Task task in TasksToShow)
{
myTable.Rows.Add(task.TaskID, task.TaskName);
}
//Adding content to the flow document
FlowDocument myFlowDocument = new FlowDocument();
myFlowDocument.Blocks.Add(myParagraph);
myFlowDocument.Blocks.Add(myTable); //This line fails :(
//Print the document
PrintDialog dialog = new PrintDialog();
if(dialog.ShowDialog() == true)
{
int margin = 5;
Size pageSize = new Size(dialog.PrintableAreaWidth - margin * 2, dialog.PrintableAreaHeight - margin * 2);
IDocumentPaginatorSource paginator = myFlowDocument;
paginator.DocumentPaginator.PageSize = pageSize;
dialog.PrintDocument(paginator.DocumentPaginator, "Flow print");
}
you can do like this.....
// Create the parent FlowDocument...
flowDoc = new FlowDocument();
// Create the Table...
table1 = new Table();
// ...and add it to the FlowDocument Blocks collection.
flowDoc.Blocks.Add(table1);
// Set some global formatting properties for the table.
table1.CellSpacing = 10;
table1.Background = Brushes.White;
pls go through this links for more info
after that you can change this depnds upon the your requirement...

Categories

Resources