I'm using GemBox.Presentation and I'm creating a large table in my PPTX file. Similar to this example, e.g.:
PresentationDocument presentation = new PresentationDocument();
Slide slide = presentation.Slides.AddNew(SlideLayoutType.Custom);
int rowCount = 100;
int columnCount = 4;
int columnWidth = 5;
Table table = slide.Content.AddTable(1, 1, columnCount * columnWidth, 0, LengthUnit.Centimeter);
for (int i = 0; i < columnCount; i++)
table.Columns.AddNew(Length.From(5, LengthUnit.Centimeter));
for (int r = 0; r < rowCount; r++)
{
TableRow row = table.Rows.AddNew(0);
for (int c = 0; c < columnCount; c++)
{
TableCell cell = row.Cells.AddNew();
TextParagraph paragraph = cell.Text.AddParagraph();
TextRun run = paragraph.AddRun(string.Format("Cell {0}-{1}", r + 1, c + 1));
}
}
presentation.Save("output.pptx");
As expected, the table doesn't fit on the slide:
So I need to split this table into multiple tables or multiple slides so that each table fits on its slide and all rows are visible.
How can I do that?
How can I find if the new TableRow will exceed the Slide height?
If you have dynamic row heights (for instance, some cells may contain multiple lines of text), then you'll need to paginate the content.
For example, see the following:
table.Frame.FormatDrawing(new PaginatorOptions() { UpdateTableRowHeights = true });
DrawingLayout tableLayout = table.Frame.Layout;
double maxHeight = presentation.SlideSize.Height - tableLayout.Top;
double currentHeight = 0;
TableRowCollection sourceRows = table.Rows;
TableRowCollection newRows = null;
int currentRowIndex = 0;
// Split the main table into multiple new tables based on the row heights.
while (currentRowIndex < sourceRows.Count)
{
currentHeight += sourceRows[currentRowIndex].Height;
// Create new slide with new table.
if (currentHeight > maxHeight)
{
currentHeight = sourceRows[currentRowIndex].Height;
Slide newSlide = presentation.Slides.AddNew(SlideLayoutType.Blank);
Table newTable = newSlide.Content.AddTable(tableLayout.Left, tableLayout.Top, tableLayout.Width, 0);
foreach (var column in table.Columns)
newTable.Columns.AddClone(column);
newRows = newTable.Rows;
}
// Move row from the main table to a new table.
if (newRows != null)
{
newRows.AddClone(sourceRows[currentRowIndex]);
sourceRows.RemoveAt(currentRowIndex);
}
else
{
++currentRowIndex;
}
}
presentation.Save("output.pptx");
If you have constant row heights, like shown in your screenshot, then you can simplify this.
For example, like the following:
int rowsPerSlide = 16;
TableRowCollection rows = table.Rows;
DrawingLayout layout = table.Frame.Layout;
for (int t = 1, tablesCount = (int)Math.Ceiling(rows.Count / (double)rowsPerSlide); t < tablesCount; t++)
{
Slide newSlide = presentation.Slides.AddNew(SlideLayoutType.Blank);
Table newTable = newSlide.Content.AddTable(layout.Left, layout.Top, layout.Width, 0);
foreach (var column in table.Columns)
newTable.Columns.AddClone(column);
for (int r = rowsPerSlide, rowsCount = Math.Min(rowsPerSlide * 2, rows.Count); r < rowsCount; r++)
{
newTable.Rows.AddClone(rows[rowsPerSlide]);
rows.RemoveAt(rowsPerSlide);
}
}
presentation.Save("output.pptx");
Related
This is my code:
Private void TAbleconvertion () {
// Table alignment issue
for (int TableCount = 1; TableCount <= wdDocConv.Tables.Count; TableCount++) {
if (wdDocConv.Tables[TableCount] != null) {
Microsoft.Office.Interop.Word.Table tbl = wdDocConv.Tables[TableCount];
tbl.AllowAutoFit = true;
Range r = tbl.Range;
Cells cells = r.Cells;
for (int count = 1; count <= cells.Count; count++) {
// Resizing width - but not working when this code move to windows server
int size = 100 / cells.Count;
Cell cell = cells[count];
cell.PreferredWidth = size;
cells.PreferredWidth = size;
Marshal.ReleaseComObject(cell);
}
}
}
}
I'm trying to create a panel(Static) in C#, were I generate multiple ListViews/GridViews in a Grid.
I know how to Fill a single existing ListView.
I've done this multiple times on ListViews I dragged onto my application using the toolbox.
I have a sqldatabase connection and I want to use data from that database to determine how many ListViews/GridViews are going to be generated.
I found a picture of what I am imagining in my head(Without the roomstatus)
If there are more ListViews/GridViews generated I want to be able to scroll down INSIDE the panel i created.
Okay, i've managed to pull it of!
private void GenerateTable()
{
SomerenLogic.Room_Service roomService = new SomerenLogic.Room_Service();
List<Room> roomList = roomService.GetRooms();
int counter = 0;
foreach (SomerenModel.Room s in roomList)
{
counter = counter + 1;
}
double wortelvan = Math.Sqrt(counter);
double column = Math.Floor(wortelvan);
double row = Math.Ceiling(wortelvan);
int columnCount = (int)(column);
int rowCount = (int)(row);
SomerenLogic.Indeling_Service indelingService = new SomerenLogic.Indeling_Service();
//Clear out the existing controls, we are generating a new table layout
tableLayoutPanel1.Controls.Clear();
tableLayoutPanel1.RowStyles.Clear();
//Clear out the existing row and column styles
tableLayoutPanel1.ColumnStyles.Clear();
tableLayoutPanel1.RowStyles.Clear();
//Now we will generate the table, setting up the row and column counts first
tableLayoutPanel1.ColumnCount = columnCount;
tableLayoutPanel1.RowCount = rowCount;
int counter2 = 1;
for (int x = 0; x < columnCount; x++)
{
//First add a column
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent));
for (int y = 0; y < rowCount; y++)
{
//Next, add a row. Only do this when once, when creating the first column
if (x == 0)
{
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent));
}
////Create the control, in this case we will add a button
//Button cmd = new Button();
//cmd.Text = string.Format("({0}, {1})", x, y);
////Finally, add the control to the correct location in the table
ListView listView1 = new ListView();
listView1.Columns.Add("");
listView1.View = View.Details;
listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
listView1.Scrollable = false;
listView1.GridLines = true;
listView1.AutoArrange = true;
List<Indeling> indelingList = indelingService.GetIndeling(counter2);
foreach (SomerenModel.Indeling s in indelingList)
{
ListViewItem la = new ListViewItem("Kamer nummer: "+(s.KamerNummer).ToString());
listView1.Items.Add(la);
ListViewItem lb = new ListViewItem("Type kamer: "+(s.TypeKamer).ToString());
listView1.Items.Add(lb);
ListViewItem lc = new ListViewItem("Plekken: "+(s.AantalBedden).ToString());
listView1.Items.Add(lc);
listView1.Height = (listView1.Items.Count * 19);
tableLayoutPanel1.Controls.Add(listView1, x, y);
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
counter2++;
}
}
}
I create excel file using NPOI dll's.
I have this code that create excel table from List<someObjects> :
IWorkbook workbook = new XSSFWorkbook();
ISheet sheet1 = workbook.CreateSheet("Sheet 1");
IRow header = sheet1.CreateRow(0);
header.CreateCell(0).SetCellValue("Id");
header.CreateCell(1).SetCellValue("Name");
header.CreateCell(2).SetCellValue("E-Mail");
header.CreateCell(3).SetCellValue("PhoneNumber");
for (int i = 0; i < list.Count(); i++)
{
IRow row = sheet1.CreateRow(i + 1);
row.CreateCell(0).SetCellValue(list[i].id);
row.CreateCell(1).SetCellValue(list[i].name);
row.CreateCell(2).SetCellValue(list[i].email);
row.CreateCell(3).SetCellValue(list[i].phoneNumber);
}
Then I make each cell bordered in the table created above.
Here is the code:
public void setBorderExcel()
{
XSSFCellStyle myStyle = (XSSFCellStyle)workbook.CreateCellStyle();
myStyle.BorderBottom = BorderStyle.Medium;
myStyle.BorderTop = BorderStyle.Medium;
myStyle.BorderLeft = BorderStyle.Medium;
myStyle.BorderRight = BorderStyle.Medium;
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle = myStyle;
}
}
}
Then I make each odd row in the table created above colored.
Here is the code:
public void setColorExcel()
{
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
if (i % 2 == 0) continue;
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle.FillForegroundColor = HSSFColor.Grey25Percent.Index;
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle.FillPattern = FillPattern.SolidForeground;
}
}
}
And here is the result that I get:
As you can see the color applied to all rows in the table while, I wanted to color only the odd rows.
My question is why I get colored all rows? And how can I make colored only specific rows?
I think I understand it. You have applied the same XSSFCellStyle instance to all cells' Style property in (setBorderExcel). So, now they all have the same instance, so when you change a property on the CellStyle of one of the cells, it's changing the CellStyle instance which is associated with all cells.
You'll most likely need two XSSFCellStyle instances. One for odd rows and another for even rows.
I tried it out, and although I'm not sure why your way doesn't work, there is an easier way with less lines (simply declare another CellStyle with grey background, and use that instead of myStyle):
XSSFCellStyle myStyle = (XSSFCellStyle)workbook.CreateCellStyle();
myStyle.BorderBottom = BorderStyle.Medium;
myStyle.BorderTop = BorderStyle.Medium;
myStyle.BorderLeft = BorderStyle.Medium;
myStyle.BorderRight = BorderStyle.Medium;
XSSFCellStyle myStyleGrey = (XSSFCellStyle)workbook.CreateCellStyle();
myStyleGrey.BorderBottom = BorderStyle.Medium;
myStyleGrey.BorderTop = BorderStyle.Medium;
myStyleGrey.BorderLeft = BorderStyle.Medium;
myStyleGrey.BorderRight = BorderStyle.Medium;
myStyleGrey.FillForegroundColor = HSSFColor.Grey25Percent.Index;
myStyleGrey.FillPattern = FillPattern.SolidForeground;
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < 4; j++)
{
if (i % 2 == 0)
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle = myStyle;
else
workbook.GetSheetAt(0).GetRow(i).GetCell(j).CellStyle = myStyleGrey;
}
}
You can remove your code for setColorExcel() and it should work as expected, setting odd rows to grey.
I'm using itextSharp to export a DataTable to a pdf table. I can export the data to a pdf table using the sample code i have posted below. The DataTable contains close to 21 columns.
The first column in the pdf (DataTable) might contain similar values for any number of rows. If the data values in first column for a group of rows is similar, i want to merge the first 3 columns of those rows as one cell.
I'm having trouble modifying the code below to achieve this.
public iTextSharp.text.Table GetItextTable(DataTable dtChartData, string reportType)
{
int intCols = dtChartData.Columns.Count; //Total number of columns
int intRows = dtChartData.Rows.Count; //Total number of rows
iTextSharp.text.Table pdfTable = new iTextSharp.text.Table(intCols, intRows);
try
{
pdfTable.BorderWidth = 1;
pdfTable.Width = 100;
pdfTable.Padding = 1;
pdfTable.Spacing = 1;
/*creating table headers */
for (int i = 0; i < intCols; i++)
{
iTextSharp.text.Cell cellCols = new iTextSharp.text.Cell();
iTextSharp.text.Font ColFont = iTextSharp.text.FontFactory.GetFont("Tahoma", 07,
iTextSharp.text.Font.BOLD);
for (int l = 0; l < dtChartData.Columns.Count; l++)
{
if (dtChartData.Columns[l].ColumnName.Contains("_"))
{
dtChartData.Columns[l].ColumnName = dtChartData.Columns[l].ColumnName.Replace("_", " ");
}
}
iTextSharp.text.Chunk chunkCols = new iTextSharp.text.Chunk(dtChartData.Columns[i].ColumnName,ColFont);
cellCols.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
if ((chunkCols.ToString().ToLower() == "ReportDetails"))
{
cellCols.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
}
}
/* loop that take values from every row in datatable and insert in itextsharp table */
for (int k = 0; k < intRows; k++)
{
for (int j = 0; j < intCols; j++)
{
iTextSharp.text.Cell cellRows = new iTextSharp.text.Cell();
iTextSharp.text.Font RowFont = iTextSharp.text.FontFactory.GetFont("Tahoma", 07);
iTextSharp.text.Chunk chunkRows = new iTextSharp.text.Chunk(dtChartData.Rows[k][j].ToString(),RowFont);
cellRows.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
cellRows.Add(chunkRows);
pdfTable.AddCell(cellRows);
}
}
}
catch (Exception ex)
{
//error handling code here removed
}
return pdfTable;
}
Have you tried to change the Colspan?
iTextSharp.text.Cell cell = new iTextSharp.text.Cell();
cell.AddElement(new Paragraph("colspan 3"));
cell.Colspan = 3;
table.AddCell(cell);
In this case, cell will span three columns.
try this. i just edited your code, not checked
here i have edited 1 line of your code and added a new line (total 2 lines of change only).
dont forget to combine headding row like this, if you need
/* loop that take values from every row in datatable and insert in itextsharp table */
for (int k = 0; k < intRows; k++)
{
for (int j = 2; j < intCols; j++)// EDIT: if all first 3 cols are same, then starts with 2
{
iTextSharp.text.Cell cellRows = new iTextSharp.text.Cell();
if(j == 2) cellRows.Colspan = 3;// ADD: it'll gives a 3 times long cell
iTextSharp.text.Font RowFont = iTextSharp.text.FontFactory.GetFont("Tahoma", 07);
iTextSharp.text.Chunk chunkRows = new iTextSharp.text.Chunk(dtChartData.Rows[k][j].ToString(),RowFont);
cellRows.HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER;
cellRows.Add(chunkRows);
pdfTable.AddCell(cellRows);
}
}
I want dynamic allocation datagridview in tablelayout.
For example, I choose number of grids, (2, 4, 9, 16...)
next, create this number of datagridview controls and place them in tablelayout.
Example:
So, how can I allocate dynamically allocate a number of Datagridview using one tablelayout
i created new Form (Form1), added new TableLayoutPanel with name t and added this code for form contructor:
public Form1()
{
InitializeComponent();
int row = 1; // number of rows
int col = 2; // number of columns (change them to see effect)
var grids = new DataGridView[row,col];
// create rows and set their height
t.RowCount = row;
t.RowStyles.Clear();
for (int r = 0; r < row; r++)
{
var style = new RowStyle();
style.SizeType = SizeType.Percent;
style.Height =(float)(1.0/row);
t.RowStyles.Add(style);
}
// create columns and set their width
t.ColumnCount = col;
t.ColumnStyles.Clear();
for (int c = 0; c < col; c++)
{
var style = new ColumnStyle();
style.SizeType = SizeType.Percent;
style.Width = (float)(1.0 / col);
t.ColumnStyles.Add(style);
}
// dynamically add grid in necessary place in layout
for(int r = 0; r<row; r++)
for (int c = 0; c < col; c++)
{
grids[r,c] = new DataGridView()
{
Dock = DockStyle.Fill,
};
t.Controls.Add(grids[r, c], c, r);
}
}