Nested Table issue with iText in .net - itext

I use iText 7.0.4.0 with my .net application to generate pdfs. But inner tables overflow when the text is long.
Outer table has 10 columns with green border and seems it has rendered fine as per the image below. Each Outer table cell contains one table with one cell inside it.But Inner Table cell has overflown when the paragraph text is large.
I use iText in a large Forms building product. Hence I've recreated the issue with simple scenario and the code is given below. Please note that the number of columns are not fixed in real usage.
Could anyone please show me the correct path to achieve this?
Here is the C# Code
private Table OuterTable()
{
var columns = GetTableColumnWidth(10);
var outerTable = new Table(columns, true);
outerTable.SetWidthPercent(100);
for (int index = 0; index < columns.Length; index++)
{
Cell outerTableCell = new Cell();
Table innerTable = new Table(new float[] { 100 });
innerTable.SetWidthPercent(100);
Cell innerTableCell = new Cell();
Paragraph paragraph = new Paragraph("ABCDEFGHIJKL").AddStyle(_fieldValueStyle);
innerTableCell.Add(paragraph);
innerTable.AddCell(innerTableCell);
outerTableCell.Add(innerTable);
outerTable.AddCell(outerTableCell);
innerTableCell.SetBorder(new SolidBorder(Color.RED, 2));
innerTableCell.SetBorderRight(new SolidBorder(Color.BLUE, 2));
outerTableCell.SetBorder(new SolidBorder(Color.GREEN, 2));
}
return outerTable;
}

Thanks mkl for spending your valuable time. I solved my issue with your idea of 'no inner tables'. This is not how to solve the issue of nested tables mentioned in the question but another way of achieving the result.
I've used "\n" in the paragraph to achieve what I want. Here is the output and the code.
private Table OuterTable()
{
var columns = GetTableColumnWidth(10);
var outerTable = new Table(columns, true);
outerTable.SetWidthPercent(100);
for (int index = 0; index < columns.Length; index++)
{
Cell outerTableCell = new Cell();
outerTableCell.Add(GetContent());
outerTable.AddCell(outerTableCell);
}
return outerTable;
}
private Paragraph GetContent()
{
int maxIndex = 3;
Paragraph paragraph = new Paragraph();
for (int index = 0; index < maxIndex; index++)
{
paragraph.Add(index + " - ABCDEFGHIJKL \n").AddStyle(_fieldValueStyle);
}
return paragraph;
}

Related

Dynamic number of columns bound to a UWP datagrid (Windows Community Toolkit)

Has anyone a sample project with a dynamic number of columns bound to a datagrid in UWP? In WPF I can get it to work with an observable collection of dynamic objects with Telerik Datagrid. But in UWP Telerik does not support dynamic objects. I have tried with the Windows Community Toolkit datagrid but failed with it too.
Dynamic number of columns bound to a UWP datagrid (Windows Community Toolkit)
derive from Samed Bejtovic's reply. We could make Dynamic number of columns in code behind with Windows Community Toolkit DataGrid. Before fill the DataGrid, we need convert the collection to DataTable, for example. The following is that load csv file and insert the data to the DataTable.
var dt = new DataTable();
bool firstLine = true;
var sr = new StreamReader("Assets\\Archive.csv");
while (sr.Peek() >= 0)
{
if (firstLine)
{
firstLine = false;
var cols = sr.ReadLine().Split(',');
foreach (string col in cols)
dt.Columns.Add(new DataColumn(col, typeof(string)));
}
else
{
var data = sr.ReadLine().Split(',');
dt.Rows.Add(data);
}
}
Then we call the FillDataGrid(dt,MyDataGrid) that could add the Columns into DataGrid base on above DataTable.
public static void FillDataGrid(DataTable table, DataGrid grid)
{
grid.Columns.Clear();
for (int i = 0; i < table.Columns.Count; i++)
{
grid.Columns.Add(new DataGridTextColumn()
{
Header = table.Columns[i].ColumnName,
Binding = new Binding { Path = new PropertyPath("[" + i.ToString() + "]") }
});
}
var collection = new ObservableCollection<object>();
foreach (DataRow row in table.Rows)
{
collection.Add(row.ItemArray);
}
grid.ItemsSource = collection;
}
DataCollection = new ObservableCollection<dynamic>();
while (reader.Read())
{
string project = reader.GetString(0);
decimal number = reader.GetDecimal(1);
DataCollection.Add(new DataSummary(project, number));
}
Datagrid supports auto generated columns. Set the items source to the collection.
https://www.reddit.com/r/UWP/comments/djzcqj/display_datatable_as_datagrid/?utm_source=share&utm_medium=web2x

Send Email from Google sheet as a table without using sheets convertor

Please check the spreadsheet below:
spreadsheet
https://docs.google.com/spreadsheets/d/1QFPO4bQfYPM4rRJ_6PYxUrYsFgVeUFx89_nZ1mNaLew/edit#gid=0
The script that I'm currently using is working fine thanks to the posts I've seen here. I just wanted to send it in a better way. I've already checked other posts and I even saw the SheetConverter but is too complicated for me.
Current Result:
https://drive.google.com/file/d/1-OQqnsRwIJaoXOnYZEtPxHy6r3buB8H7/view?usp=sharing
Please check image for the desired result. Thanks!
https://drive.google.com/file/d/1p7cJBTyaZ1ZqI5Jv5WWOGg6_Q-JegfHj/view?usp=sharing
You can create an html table, like this:
function sendEmail(data){
MailApp.sendEmail({
to: "example#mail.com",
subject: "Example",
htmlBody:"<html><body>" + createTable(data)+ "</body></html>"});
}
function createTable(data){
var cells = [];
var table = "<html><body><br><table border=1><tr><th>Start Date</th><th>End Date</th><th>Leave dates</th><th>Status</th></tr>";
for (var i = 0; i < data.length; i++){
cells = data[i].toString().split(",");
table = table + "<tr></tr>";
for (var u = 0; u < cells.length; u++){
table = table + "<td>"+ cells[u] +"</td>";
}
}
table=table+"</table></body></html>";
return table;
}
Supposing you already have the data in a 2D array (rows and columns values).

How to add rows to TableView without having any data model

I'm fairly new to javafx, so please bear with me if my question is unclear. I've a TableView which need to be populated using an ObservableList.
The code below populates my "data" with the arraylists generated out of the Map, which in turn is used to add rows to my table.
TableView<ArrayList> table = new TableView<>();
ObservableList<ArrayList> data = FXCollections.observableArrayList();
for(int i=0;i<listSelectedVerticesIds.size();i++){
ArrayList<String> tempString = new ArrayList<>();
for(Map.Entry<String,String> temp2 : mapVertex.get(listSelectedVerticesIds.get(i)).entrySet()){
tempString.add(temp2.getValue());
}
data.add(tempString);
}
table.setItems(data);
However, I do not see the table populated with the list in "data". I'm guessing this is because there is no data binding (using setCellValueFactory). However, as you can see I dont have a data model class. All of my data comes from the Map as strings which I would like to populate in my tableview.
Please suggest.
Here is a simple way to do it that works great. You don't need a data structure to populate a table. You only see that because that's what most examples show. It is an extremely common use case to populate a table from a database or a file. I don't understand why this is so hard to find examples for. Well, hope this helps.
private TableView<ObservableList<StringProperty>> table = new TableView<>();
private ArrayList<String> myList = new ArrayList<>();
private void updateTableRow() {
for (int row = 0; row < numberOfRows; row++) {
ObservableList<StringProperty> data = FXCollections.observableArrayList();
for (int column = 0; column < numberOfColumns; column++) {
data.add(column, new SimpleStringProperty(myList.get(row + (column * numberOfRows))));
}
table.getItems().add(data);
}
}

EPPlus chart(pie,barchart) selected(B2,B36,B38) .. etc excel cells

I have similar to the link below problem.
EPPlus chart from list of single excel cells. How?
I tried the code but it shows it twice in the chart. For example:
This code show excel chart -> select data-> horizontal(category) axis labels tab you show 100,100,300,600 write. What is the reason for this? The chart is written twice the first data I did not find a solution to the problem.
I think you just discovered a bug with EPPlus. Shame on me for not noticing that with that post you reference. It seems that when using the Excel union range selector (the cell names separated by commas) the iterator for the ExcelRange class returns a double reference to the first cell, in this case B2.
A work around would be to use the other overload for Series.Add which will take two string ranges. Here is a unit test that show the problem and the workaround:
[TestMethod]
public void Chart_From_Cell_Union_Selector_Bug_Test()
{
var existingFile = new FileInfo(#"c:\temp\Chart_From_Cell_Union_Selector_Bug_Test.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var pck = new ExcelPackage(existingFile))
{
var myWorkSheet = pck.Workbook.Worksheets.Add("Content");
var ExcelWorksheet = pck.Workbook.Worksheets.Add("Chart");
//Some data
myWorkSheet.Cells["A1"].Value = "A";
myWorkSheet.Cells["A2"].Value = 100; myWorkSheet.Cells["A3"].Value = 400; myWorkSheet.Cells["A4"].Value = 200; myWorkSheet.Cells["A5"].Value = 300; myWorkSheet.Cells["A6"].Value = 600; myWorkSheet.Cells["A7"].Value = 500;
myWorkSheet.Cells["B1"].Value = "B";
myWorkSheet.Cells["B2"].Value = 300; myWorkSheet.Cells["B3"].Value = 200; myWorkSheet.Cells["B4"].Value = 1000; myWorkSheet.Cells["B5"].Value = 600; myWorkSheet.Cells["B6"].Value = 500; myWorkSheet.Cells["B7"].Value = 200;
//Pie chart shows with EXTRA B2 entry due to problem with ExcelRange Enumerator
ExcelRange values = myWorkSheet.Cells["B2,B4,B6"]; //when the iterator is evaluated it will return the first cell twice: "B2,B2,B4,B6"
ExcelRange xvalues = myWorkSheet.Cells["A2,A4,A6"]; //when the iterator is evaluated it will return the first cell twice: "A2,A2,A4,A6"
var chartBug = ExcelWorksheet.Drawings.AddChart("Chart BAD", eChartType.Pie);
chartBug.Series.Add(values, xvalues);
chartBug.Title.Text = "Using ExcelRange";
//Pie chart shows correctly when using string addresses and avoiding ExcelRange
var chartGood = ExcelWorksheet.Drawings.AddChart("Chart GOOD", eChartType.Pie);
chartGood.SetPosition(10, 0, 0, 0);
chartGood.Series.Add("Content!B2,Content!B4,Content!B6", "Content!A2,Content!A4,Content!A6");
chartGood.Title.Text = "Using String References";
pck.Save();
}
}
Here is the output:
I will post it as an issue on their codeplex page to see if they can get it fixed for the next release.

Unable to add data in archive table in Entity Framework

I wrote the code to update my table (SecurityQuestionAnswer) with new security password questions and move to old questions to another table (SecurityQuestionAnswersArchives). Total no of security questions is 3. I am able to update the current table, but when I add the same rows to history table, it shows weird data: only two records are added instead of 3 and the data is also duplicated. My code is as follows:
if (oldQuestions.Any())
{
var oldquestionstoarchivelist = new List<SecurityQuestionAnswersArchives>();
var oldquestionstoarchive =new SecurityQuestionAnswersArchives();
for (int i = 0; i < 3; i++)
{
oldquestionstoarchive.Id = oldQuestions[i].Id;
oldquestionstoarchive.SecurityQuestionId = oldQuestions[i].SecurityQuestionId;
oldquestionstoarchive.Answer = oldQuestions[i].Answer;
oldquestionstoarchive.UpdateDate = oldQuestions[i].UpdateDate;
oldquestionstoarchive.IpAddress = oldQuestions[i].IpAddress;
oldquestionstoarchive.SecurityQuestion = oldQuestions[i].SecurityQuestion;
oldquestionstoarchive.User = oldQuestions[i].User;
oldquestionstoarchivelist.Add(oldquestionstoarchive);
}
user.SecurityQuestionAnswersArchives = oldquestionstoarchivelist;
//await Store.UpdateAsync(user);
_dbContext.ArchiveSecurityQuestionAnswers.AddRange(oldquestionstoarchivelist);
_dbContext.SecurityQuestionAnswers.RemoveRange(oldQuestions);
await _dbContext.SaveChangesAsync();
oldquestionstoarchivelist.Clear();
}
UPDATE 1
The loop looks fine, It iterates three times(0,1,2), which is expected. First issue is with AddRange function to which I was passing a list , but it takes an IEnumerable input, I rectified it using following code.
IEnumerable<SecurityQuestionAnswersArchives> finalArchiveses = oldquestionstoarchivelist;
_dbContext.ArchiveSecurityQuestionAnswers.AddRange(finalArchiveses);
The other issue is duplicate data , which I am unable to figure out where the issue is. Please help me in finding this out.
Your help is much appreciated !
Got it ! Just sharing in case anybody has same issue.
The problem was with initialization at wrong place. I moved
var oldquestionstoarchive =new SecurityQuestionAnswersArchives();
in side the Forloop, now the variable will hold the unique values over each iteration.
var oldquestionstoarchivelist = new List<SecurityQuestionAnswersArchives>();
for (int i = 0; i < 3; i++)
{
var oldquestionstoarchive = new SecurityQuestionAnswersArchives();
oldquestionstoarchive.SecurityQuestionId = oldQuestions[i].SecurityQuestionId;
oldquestionstoarchive.Answer = oldQuestions[i].Answer;
oldquestionstoarchive.UpdateDate = oldQuestions[i].UpdateDate;
oldquestionstoarchive.IpAddress = oldQuestions[i].IpAddress;
oldquestionstoarchive.SecurityQuestion = oldQuestions[i].SecurityQuestion;
oldquestionstoarchive.User = oldQuestions[i].User;
oldquestionstoarchivelist.Add(oldquestionstoarchive);
}