Add cell having a table to outer table using itextsharp - c#

I'm trying to add a cell having a table to outer table.
I'm getting following error.
"Adding a cell at the location (6,0) with a colspan of 1 and a rowspan
of 1 is illegal (beyond boundaries/overlapping)"
This seems to be like a bug in itextsharp.
I find a each control in html table. If this control is Table i call
it 'tblinner'.
I'm finding a control(in this case all controls are labels) inside
'tblinner' and adding it to itextsharp table.
How may i overcome this?
for (int i = 0; i < tblInner.Rows.Count; i++)
{
iTextSharp.text.Table tblnested = new iTextSharp.text.Table(4);
iTextSharp.text.Table tblnestedbig = new iTextSharp.text.Table(1);
iTextSharp.text.Cell pdfTCell = new iTextSharp.text.Cell();
iTextSharp.text.Cell pdfTCellbig = new iTextSharp.text.Cell();
foreach (TableCell tCellInner in tblInner.Rows[i].Cells)
{
pdfTCell = new iTextSharp.text.Cell();
int cc = tblInner.Rows[i].Cells.Count;
Control tControlInnerLabel = tCellInner.Controls[0];
pdfTCell = AddControlBGToPDFTable(tControlInnerLabel, tblnested);//This function adds the control such as lable or image to tblnested
tblnestedbig.AddCell(pdfTCell);
}
pdfTCellbig.AddElement(tblnestedbig);
pdfTable.AddCell(pdfTCellbig);//i get error here
}
Here is what 'AddControlBGToPDFTable' does.
private static iTextSharp.text.pdf.PdfPCell AddControlBGToPDFTable(Control tControl, iTextSharp.text.pdf.PdfPTable pdfTable)
{
(tControl is Label)
{
Label lbl = (Label)tControl.FindControl(tControl.ID);
// add some style to control
iTextSharp.text.pdf.PdfPCell pdfTable2Cell2 = null;
pdfTable2Cell2.Colspan = 1;
pdfTable2Cell2 = pdfOrigTCell;
pdfTable2Cell2.AddElement(new iTextSharp.text.Phrase(25f,lbl.Text.Replace("<br>", "\r\n").Replace("<br />", "\r\n"), new iTextSharp.text.Font(iTextSharp.text.Font.HELVETICA, 12, style)));
pdfTable.AddCell(pdfTable2Cell2);
return pdfTCell;
}
}
It takes a control passed to it.
Create a cell and put this control to cell and add the cell to table
that is passed as param to it.

you should post also code for method AddControlBGToPDFTable, that we can see what properties are you setting to cell.
Instead of creating cell with label you can use PdfPCell and PdfPTable.
iTextSharp.text.pdf.PdfPCell cell = new iTextSharp.text.pdf.PdfPCell();
cell.Phrase = new iTextSharp.text.Phrase("some text");

Related

How to assign value to text box control inside the table column in C# coding file?

I am creating asp.net web form. in that i am creating dynamic tables in which particular column is numeric text box control.
i don't know how to assign and get values from the text box control.. my coding as follow..
for (int i = 0; i < my_DataTable.Rows.Count; i++)
{
HtmlTableRow _Row = new HtmlTableRow();
HtmlTableCell Col = new HtmlTableCell();
Col.InnerText = my_DataTable.Rows[i]["itmCode"].ToString();
_Row.Controls.Add(Col);
Col = new HtmlTableCell();
_Row.Controls.Add(Col);
Col.InnerHtml = "<input type='number' value='0'>";
_Row.Controls.Add(Col);
my_Table.Rows.Add(_Row);
}
In a paricular method, i need to assign the value to the text box control also needs to get the value existing value.. so i try follow as below
var no_1 = my_Table.Rows[0].Cells[1].InnerText;
If i check the no_1, it has the textbox, but i don't know how to access the current value and assign new value..
can anyone help me how to achieve this..
One thing you have to keep in mind while working with Dynamic Controls is that whenever a postback has occurred you will lose the dynamically created controls(as the postback calls the Page_load() event so if you don't have them at the load event they will not be generated and hence will not be displayed.). So, it is always better to re-render the controls in the load event.
So, in order to get the value of the dynamically assigned controls (either HTML or Asp.net) here is how i would do that.
First, create a holder which will be used to store the controls in the page either with runat="server"(So, you can access that control in the backend). In your case, that control is my_Table. Then use the Session/ViewState to keep a track of all the created dynamic controls which can be used re-render the controls with their values as:
To add a new control in the page it would be like this:
var cnt = _findRelated("txtDynamic") + 1; //for all the dynamic text boxes i am using the prefix of txtDynamic just to keep SOC.
var nId = $"txtDynamic-{cnt}";
var _ctrl = new HtmlInputText("Integer")
{
Name = nId,
ID = nId,
//Value="Default Value" //uncomment to assign a default value
};
_ctrl.Attributes.Add("runat", "server");
var row = new System.Web.UI.HtmlControls.HtmlTableRow();
var newCell = new HtmlTableCell();
newCell.Controls.Add(_ctrl);
row.Cells.Add(newCell);
my_Table.Rows.Add(row);
Session.Add(cnt.ToString(), _ctrl); //here i am using session to manage the controls but you can also use the ViewState
In the above code i am using HtmlInputText to generate an <input type="number"></input> with it's constructor taking the type string more can be read at:HtmlInputText.
The _findRelated() method is used to get the number of dynamic text controls appended to the Form. It is defined as:
private int _findRelated(string prefix)
{
string reqstr = Request.Form.ToString();
return ((reqstr.Length - reqstr.Replace(prefix, "").Length) / prefix.Length);
}
To set the value of the dynamically added control we can do something like this(if not assigned at the creation):
var cell = my_Table.Rows[_myTable.Rows.Count-1].cells[0]; //here i have assumed it is in the last row and in the first cell you can change the index to be anything.
var txtDynamic = cell.Controls.OfType<HtmlInputText>().FirstOrDefault();//getting the control
txtDynamic.Value = "<Some thing new>"; //setting the value
Now, to get the assigned the value:
var cell = my_Table.Rows[_myTable.Rows.Count-1].cells[0]; //here i have assumed it is in the last row and in the first cell you can change the index to be anything.
var txtDynamic = cell.Controls.OfType<HtmlInputText>().FirstOrDefault();//getting the control
//now use the .Value property of the control to get the value as:
var nValue = txtDynamic.Value;
And as we know the dynamically added controls will be lost on the postback event then we can create a method which will use the controls stored in the Session and re-render them with their values as:
private void _renderControls()
{
try
{
if (Session.Count > 0)
{
for (int k = 0; k < Session.Count; k++)
{
if (Session[k] != null)
{
var _ctrl = new HtmlInputText("Integer") //you can make it dynamic to add different types of input control
{
Name = ((HtmlInputText)Session[k]).ID,
ID = ((HtmlInputText)Session[k]).ID,
Value = ((HtmlInputText)Session[k]).Value
};
if (_ctrl != null)
{
_ctrl.Attributes.Add("runat", "server");
var row = new System.Web.UI.HtmlControls.HtmlTableRow();
var newCell = new HtmlTableCell();
newCell.Controls.Add(_ctrl);
row.Cells.Add(newCell);
my_Table.Rows.Add(row);
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
Now, let's modify the Page_load() event to call this method on every postback as:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
_renderDynamic(); // this method will be called if there is an postback event to re-render the dynamic controls
}
}
Note:
This is just a sample(there can be a lot better approaches out there).
I have used HtmlInputText with property as Integer to create ainput[type="number"].

Add ContextMenuStrips to multiple DataGridViews on multiple TabPages

I am trying to load multiple DataTables into DataGridViews in separate tabpages of a TabControl, the DataTables are stored in a Dictionary which is in turn stored in a DataObject class.
I can get everything displaying correctly but when I try to add loop through the Datagridview Header to add a contextmenustrip, for some reason I can get it to work for the first DataGridView but subsequent DataGridViews do not have the context menu applied? I have tried adding a print statentment just before the foreach loop and the DataGridView gets a column count of zero…so im guessing that’s why the foreach loop isn’t doing anything…but all the data is still displayed correctly in the dataGridViews in their respective tabs…any help in pointing out what I’m missing would be greatly appreciated.
Regards
Amarino
Code given below
List<ImportObject> lImportObjects = new List<ImportObject>();
private void loadImportFilesToScreen(List<ImportObject> lImportObjects)
{
foreach (ImportObject lImportObject in lImportObjects) {
DisplayImportFiles(lImportObject);
}
}
public void DisplayImportFiles(ImportObject pImportObject)
{
string lTabName="";
//load DataGridView with DataTable
/*
foreach (KeyValuePair<string, DataTable> lDT in pImportObject.DataTableDictionary)
{
lTabName = DisplayTabsInApp(pImportObject.FileName + "_" + lDT.Key, lDT.Key);
LoadDatatableIntoGrid(lDT.Value, lTabName);
}
*/
for (int i = 0; i < pImportObject.DataTableDictionary.Count; i++)
{
KeyValuePair<string, DataTable> lItem = pImportObject.DataTableDictionary.ElementAt(i);
string lKey = lItem.Key;
DataTable lDT = lItem.Value;
lTabName = DisplayTabs(pImportObject.FileName + "_" + lKey, lKey);
LoadDatatableIntoGrid(lDT, lTabName);
lDT = null;
}
}
public string DisplayTabs(string pTabName, string pSheetName)
{
// Create a new Tab Page for this file. Set heading, set name.
TabPage lTabPage_NewFile = new TabPage();
lTabPage_NewFile.Text = pTabName;
lTabPage_NewFile.Name = "TAB_PAGE_" + pTabName;
tabControl_ImportFiles.TabPages.Add(lTabPage_NewFile);
return lTabPage_NewFile.Name;
}
public void LoadDatatableIntoGrid(DataTable pDataTable, string pTabName) {
DataGridView lDGV = new DataGridView();
lDGV.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing;
lDGV.RowHeadersVisible = false;
BindingSource BindingSource1 = new BindingSource(); //create new data binding source
BindingSource1.DataSource = pDataTable; //SetData source
lDGV.DataSource = BindingSource1;
lDGV.RowHeadersVisible = true;
tabControl_ImportFiles.TabPages[pTabName].Controls.Add(lDGV);
//DataGridView lDGV = tabControl_ImportFiles.TabPages[pTabName].Controls[0] as DataGridView;
PrintToConsoleInARD("DataGridView Column Count: " + lDGV.Columns.Count.ToString());
bool runOnce = true;
foreach (DataGridViewColumn lDGVColumn in lDGV.Columns) {
lDGVColumn.HeaderCell.ContextMenuStrip = lCMS_ColumnHeaders;
}
lDGV.Dock = DockStyle.Fill;
lDGV.VirtualMode = true;
BindingSource1 = null;
lDGV = null;
}
I am confident the reason for this is because the “tab page” is not displayed. As the trace is described inside the LoadDatatableIntoGrid method… if you put a breakpoint at the line…
tabControl_ImportFiles.TabPages[pTabName].Controls.Add(lDGV);
Add a watch to the variable lDGV.Columns.Count… will show that IDGV has zero (0) columns. Execute the line above and magically, the grid IDGV has columns. This appears correct since this is the first “tab page” and it is the active (displayed) tab page. Point being… if you do not add the grid to a “Active/Shown/Displayed” tab page most UI code will be ignored. This is why the next time around; the grid will be empty because the grid is added to a non “active/shown/displayed” tab page.
A simple solution is to simply “Show” the tab page before you add the grid to it. This appears to fix the issue you describe. Add the line below before the line above…
tabControl_ImportFiles.TabPages[pTabName].Show();
Hope this helps.

Changing cell data on gridView on DevExp

I'm writing an audit program and I've got a problem. I use DevExp on the list, if the staff is audited on the control part, I would like to put a red cross if the green tick is not audited. But I could not do it with DevExp. Could you help?
gridView1 view: http://i.hizliresim.com/7Dqd75.jpg
I tried them
for (int i = 0; i < gridView1.RowCount; i++)
{
if (gridView1.GetRowCellValue(i, colAUDITSTATUS).ToString() == "False")
{
gridView1.SetRowCellValue(i, colCHECK, btnCheck);
}
}
I have identified the okButton object in the properties of gridView1 in the In-place Editor Repository.
The code works fine, but it does not change.
Set the ColumnEdit proprety of colAUDITSTATUS column to an instance of RepositoryItemCheckEdit and handle it there (see the comments in my code).
var repositoryItemCheckEdit1 = new DevExpress.XtraEditors.Repository.RepositoryItemCheckEdit();
repositoryItemCheckEdit1.AutoHeight = false;
repositoryItemCheckEdit1.Caption = "Audited";
repositoryItemCheckEdit1.CheckStyle = DevExpress.XtraEditors.Controls.CheckStyles.UserDefined; // <-- important!!!!!
repositoryItemCheckEdit1.Images = imageList; // <--- put an image control on your form and add red and green icons in it
repositoryItemCheckEdit1.ImageIndexChecked = 0; // <-- depends on your indexes in imageControl
repositoryItemCheckEdit1.ImageIndexUnhecked = 1; // <-- depends on your indexes in imageControl
repositoryItemCheckEdit1.Name = "repositoryItemCheckEdit1";
colAUDITSTATUS.ColumnEdit = this.repositoryItemCheckEdit1;

WPF - DataGridColumn Width not Returning Expected Value

.NET4.0 : I'm building a DataGrid in a codebehind, so I'm not using any XAML. C# only. When the user right clicks anywhere in the column header, I want to show a context menu. Here's some code to give you an idea:
public void MakeAllColumns()
{
for (int i = 0; i < AllColumnDisplayNames.Length; i++)
{
// create a new column depending on the data to be displayed
DataGridTextColumn col = new DataGridTextColumn();
col.MaxWidth = 300;
// create a new Textblock for column's header and add it to the column
TextBlock headerText = new TextBlock() { Text = AllColumnDisplayNames[i] };
col.Header = headerText;
/// create a new context menu and add it to the header
ContextMenu menu = new ContextMenu();
headerText.ContextMenu = menu;
// build the context menu depending on the property
menu.Items.Add(new Button() { Content = "FOOBAR" });
// add the bindings to the data
col.Binding = new Binding(AllColumnBindings[i]);
AllColumns.Add(AllColumnDisplayNames[i], col);
}
}
The problem with this approach is that the user needs to click on the actual TextBox in order to activate the context menu, as opposed to anywhere on the header.
As I can't think of a way to make the TextBox fill the header width, all I can think to do is change the TextBox width property to bind to the column's width. The columns stretch to fit their content, and as such they have different widths. However, when I print all the columns ActualWidth properties to console, it says that they all have width 20, which is not what my GUI looks like. How can I get the column width that corresponds to how it looks in my GUI?
To you solve your problem must exchange o your body method by this body:
This code was tested:
for (int i = 0; i < AllColumnDisplayNames.Length; i++)
{
// create a new column depending on the data to be displayed
DataGridTextColumn col = new DataGridTextColumn();
col.MaxWidth = 300;
/// create a new context menu
ContextMenu menu = new ContextMenu();
// build the context menu depending on the property
menu.Items.Add(new Button() { Content = "FOOBAR" });
// create a new column's header and add it to the column
DataGridColumnHeader head = new DataGridColumnHeader() { Content = AllColumnBindings[i] };
head.ContextMenu = menu;//add context menu to DataGridColumnHeader
col.Header = head;
// add the bindings to the data
col.Binding = new Binding(AllColumnBindings[i]);
AllColumns.Add(AllColumnDisplayNames[i], col);
}
Instead of using TextBlock I used DataGridColumnHeader, which has the ContextMenu property, thus occupying all the space (height and width) of the Header.

LayoutGrid SetRow and SetColumn not working as intended

I have code that creates a button for each object in a list. When each object is created it is given a name that corresponds to the row and column (i.e. name = row1col2). Each button is generated dynamically, added to the grid and then the row/column are set. At a later time I need to gather the "selected" button data so I can perform actions on the data they represent. When I attempt to get the control data from the buttons everything is fine, except for the grid row/column data. It remains the same for all of the selected rows and columns in a grid.
Creating buttons:
for (int i = 1; i < row.StackCount+1; i++)
{
//create button for the column
stackButton = new Button();
stackButton.Height = ((newRow.Height - 2));
stackButton.Width = ((newRow.Width / row.StackCount) - 2);
stackButton.Background = new SolidColorBrush(Colors.White);
//add the button border
stackButton.BorderBrush = new SolidColorBrush(Colors.Black);
stackButton.BorderThickness = new Thickness(1);
stackButton.Style = Application.Current.Resources["flatButton"] as Style;
//add the button name
stackButton.Name = "Row" + row.LineNumber + "Col" + (i - 1).ToString();
//add the event handler to the button
stackButton.Click += new RoutedEventHandler(stackButton_Click);
//add a new column
newRow.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(newRow.Width, GridUnitType.Star) });
//put the button into the grid
newRow.Children.Add(stackButton);
Grid.SetRow(stackButton, 0);
Grid.SetColumn(stackButton, i-1);
}
Getting the Button data back
g = (Grid)b.Child;
foreach (Button currentButton in g.Children)
{
if (((SolidColorBrush)currentButton.Background).Color == Colors.Gray)
{
//create a stack object
buttonData.StartDate = DateTime.Now;
buttonData.LotNumber = LotDisplay.Text;
buttonData.RoomID = SilverGlobals.CurrentRoom.RoomID;
buttonData.RoomCol = Grid.GetColumn(currentButton);
buttonData.RoomRow = Grid.GetRow(currentButton);
buttonData.TrayCount = int.Parse(currentButton.Content.ToString());
buttonData.Status = 0;
//add stack object to list of stack objects
stacks.Add(buttonData);
}
}
I know this must be something small I am missing. Anyone got any ideas?
Although the comment in your second section of code says:
//create a stack object
you don't actually create a new stack object so it is simply overwriting the single instance of buttonData on each iteration. The values for row and column that you see at the end are the last iteration's values.
The net effect is that stacks is a collection of all the same instance of an object instead of a collection of separate instances.
This is just a shot in the dark, but based on this question and this question, it might be that you need to set the Row and Column properties before you add the button to its parent - something like this:
//put the button into the grid
Grid.SetRow(stackButton, 0);
Grid.SetColumn(stackButton, i-1);
newRow.Children.Add(stackButton);

Categories