I've already got my custom header drawing in my GridView using SetRenderMethodDelegate on the header row within the OnRowCreated method. I'm having problems trying to add LinkButtons to the new header row though.
This is what the RenderMethod looks like:
private void RenderSelectionMode(HtmlTextWriter output, Control container)
{
TableHeaderCell cell = new TableHeaderCell();
cell.Attributes["colspan"] = container.Controls.Count.ToString();
AddSelectionModeContents(cell);
cell.RenderControl(output);
output.WriteEndTag("tr");
HeaderStyle.AddAttributesToRender(output);
output.WriteBeginTag("tr");
for(int i = 0; i < container.Controls.Count; i++)
{
DataControlFieldHeaderCell cell = (DataControlFieldHeaderCell)container.Controls[i];
cell.RenderControl(output);
}
}
private void AddSelectionModeContents(Control parent)
{
// TODO: should add css classes
HtmlGenericControl label = new HtmlGenericControl("label");
label.InnerText = "Select:";
selectNoneLK = new LinkButton();
selectNoneLK.ID = "SelectNoneLK";
selectNoneLK.Text = "None";
//selectNoneLK.Attributes["href"] = Page.ClientScript.GetPostBackClientHyperlink(selectNoneLK, "");
//selectNoneLK.Click += SelectNoneLK_Click;
selectNoneLK.Command += SelectNoneLK_Click;
selectAllLK = new LinkButton();
selectAllLK.ID = "SelectAllLK";
selectAllLK.Text = "All";
//selectAllLK.Attributes["href"] = Page.ClientScript.GetPostBackClientHyperlink(selectAllLK, "");
//selectAllLK.Click += SelectAllLK_Click;
selectAllLK.Command += SelectAllLK_Click;
parent.Controls.Add(label);
parent.Controls.Add(selectNoneLK);
parent.Controls.Add(selectAllLK);
}
As you can see, I have tried different ways to get my LinkButtons working (none have worked though). The LinkButtons are rendered as plain anchor tags, like this: <a id="SelectNoneLK">None</a>
I know there is something wrong with the fact that the ID looks like that, since I am using a Master page for this and the ID should be something much longer.
Any help would be appreciated!
Nick
I'd guess that since cell is not part of the control hierarchy (you never add it to the table), the LinkButton's never find an IContainer parent to rewrite their ID's.
I tend to solve these types of issues using the excellent RenderPipe control that allows me to declare my controls in one place, but render them somewhere else.
Related
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"].
I want to hide or show section of my webpage. The problem is that the css Id's are created in the code behind. I do not know how to access them. Any help would be greatly appreciated.
In the fonction ShowColumn KanbanColum should be collapseSection0, collapseSection1 .... And collapseSection collapseDiv0, collapseDiv1 .... but I cant access them. since does variables are created in the background.
protected void ShowColumn(object sender, EventArgs e)
{
kanbanColumn.Visible = true;
collapseSection.Visible = false;
}
public void PopulateLists(int numberOfColumns,List<string> lstColumnsNames, List<int> lstTaskPerColumns, List<string> lstTaskText, List<string> headerColorOptions)
{
HtmlGenericControl li;
string colorChosen;
for (int j = 0; j < numberOfColumns; j++)
{
System.Web.UI.HtmlControls.HtmlGenericControl CollapseDiv = new System.Web.UI.HtmlControls.HtmlGenericControl("div");
CollapseDiv.ID = "collapseSection" + j;
CollapseDiv.Attributes.Add("class", "collapsed-kanban");
CollapseDiv.Style.Add("background-color", "#f4ce46");
dragListColumns.Controls.Add(CollapseDiv);
ImageButton expanImage = new ImageButton();
expanImage.ImageUrl= "~/images/maximize.png";
expanImage.ID = "expandImageId" + j;
expanImage.Height = 20;
expanImage.Width = 20;
expanImage.Attributes.Add("class", "second-menu-icon");
expanImage.Attributes.Add("OnClick", "ShowColumn");
CollapseDiv.Controls.Add(expanImage);
Label lblCollapse = new Label();
lblCollapse.Text = lstColumnsNames[j];
lblCollapse.Attributes.Add("class", "vertical-text");
CollapseDiv.Controls.Add(lblCollapse);
}
}
Here is a image to visual represent the code.
What can I do to be able to use the cssId's that I have created in the background or is there another way to do around the problem. Thank you very much.
Maybe you mean that you find different IDs on the generated web page than the ones you define in codebehind?
You might want to take a look at the ClientIDMode property of asp net tags.
If you don't specify it clearly, ASP.NET generates some weird IDs for your html.
Check THIS article and see if it's what you're looking for.
If you want to manage the ids from the page side, you NEED javascript.
Use JQuery to easily access the ids
I am trying to add a ConfirmButtonExtender to my controls collection within a custom control at runtime but can not figure out why the extender will not wire to the button that is being added to the controls collection in the same CreateChildControls method. I did a simple test and added a button explicitly to an aspx page and then creating the extender dynamically in the PreRender of the the .cs file of that page and it still did not work. It seems that the only way to get this to work is to have the actual tags on the .aspx page.
Am I missing something?
protected virtual void CreateChildControls(System.Resources.ResourceManager rm)
{
valValidationSummary = new ValidationSummary();
valValidationSummary.ID = "valValidationSummary";
valValidationSummary.ShowSummary = true;
valValidationSummary.HeaderText = rm.GetString("ValidationSummary");
valValidationSummary.CssClass = "error";
btnGetRates = new LocalizedButton();
btnGetRates.ID = "btnGetStats";
btnGetRates.TextResource = rm.GetString("SubmitButton");
btnGetRates.Text = rm.GetString("SubmitButton");
btnGetRates.CssClass = "inputfield";
btnGetRates.Click += new System.EventHandler(OnSubmitButton_Click);
btnConfirmation = new ConfirmButtonExtender();
btnConfirmation.ID = "rfBtnSubmit_Confirm";
btnConfirmation.ConfirmText = rm.GetString("BAUConfrimation");
btnConfirmation.TargetControlID = "btnGetStats";
this.Controls.Add(btnConfirmation);
this.Controls.Add(valValidationSummary);
this.Controls.Add(btnGetRates);
}
Dumb mistake, I was not rendering the control.
I have some logic that loops and adds a new Panel control to another control:
for (int segmentIndex = 0; segmentIndex < segments.Length; ++segmentIndex)
{
holder.Controls.Add(new Panel() { Width = Unit.Percentage(segments[segmentIndex] / segmentsSum * 100), CssClass = String.Format("segment segment-{0}", segmentIndex) });
}
container.Controls.Add(holder);
This works great, but there are a few values that I need to store on each panel within the loop. I need to be able to access these values in both c# and javascript, once the control is rendered on the page. What would be the best way to achieve this? I've used the Tag property before on some controls, but a Panel doesn't have one.
Thanks so much
It sounds like you need to add markup inside of the Panel, is that correct? If so, you can add a control to the Panel control's Controls collection, such as a Label or a LiteralControl.
The following (non-tested) code illustrates this point:
for (int segmentIndex = 0; segmentIndex < segments.Length; ++segmentIndex)
{
var p = new Panel() { ... };
var innerContent = new LiteralControl("<p>Hello, World!</p>");
p.Controls.Add(innerContent);
holder.Controls.Add(p);
}
container.Controls.Add(holder);
Alternatively, instead of a LiteralControl you could add a Label, a Button... whatever you need.
Add a HiddenField to your panel. It will render in HTML as <input type="hidden" /> so it's invisible, accessible for your server code and also for your javascript.
LiteralControl innerContent = new LiteralControl("<p>Hello, World!</p>");
HiddenField hiddenContent = new HiddenField() { ID = "hiddenContent", Value = "My hidden content" };
p.Controls.Add(innerContent);
p.Controls.Add(hiddenContent);
I have built a table in a class GetData.cs
public Table BuildTable()
{
Table tButtons = new Table();
TableRow tRow = new TableRow();
TableCell tCell = new TableCell();
long lColumn = 0;
long lPreviousColumn = 0;
long lRow = 0;
long lPreviousRow = 0;
long lLanguage = 0;
long lPreviousLanguage=0;
OpenConnection();
ButtonData();
Int32 lRowOrd = aReader.GetOrdinal("RowNumber");
Int32 lColOrd = aReader.GetOrdinal("ColumnNumber");
Int32 lLangOrd = aReader.GetOrdinal("Language");
Int32 lLabelOrd = aReader.GetOrdinal("Label");
while (aReader.Read())
{
lRow = IsDbNull(aReader,lRowOrd);//first get our column number
lColumn = IsDbNull(aReader,lColOrd);//first get our column number
lLanguage = IsDbNull(aReader,lLangOrd);//first get our column number
if (lPreviousRow != lRow)//we have a new row
{
if (lPreviousRow != 0)//then we are working on one and need to save it before moving on
{
tButtons.Rows.Add(tRow);//add the new row to the table
}
lPreviousRow = lRow;//remember the value for next time
tRow = new TableRow();
tRow.Visible = true;
//*******put the category titles in here somewhere
}
if (lPreviousColumn != lColumn)//we have a new column
{
if (lPreviousColumn != 0)//then we are working on one and need to save it before moving on
{
tRow.Cells.Add(tCell);//add the new cell to the row
}
lPreviousColumn = lColumn;//remember the value for next time
//*******add the cell colors
if (lPreviousLanguage != lLanguage)//we have a new column
{
lPreviousLanguage = lLanguage;//remember the value for next time
tCell.Text = IsDbNull(aReader,lLabelOrd,"");
//*******add the languages to properties
}
tCell = new TableCell();
tCell.Visible=true;
}
}
CloseConnection();
tButtons.Visible=true;
return tButtons;
}
In my Default.aspx.cs page I have
GetData Buttons = new GetData();//create a reference to the class
ButtonTable = Buttons.BuildTable();
OutPut.Text = ButtonTable.Rows.Count.ToString();
In Default.aspx
<asp:Table runat="server" ID="ButtonTable" />
<asp:Label runat="server" ID="OutPut" />
Output shows 4 rows, but table is empty.
<table id="ButtonTable" border="0"></table>
What am I doing wrong?
What the heck am I missing?
Apparently, a lot. In your markup, you have declared an instance of a System.Web.UI.WebControls.Table. In your instance of the Page class, this will have a variable name of "ButtonTable". It will also be automatically added to the Page.Controls collection. When the page is going to be rendered, the Controls collection will be iterated and rendered in turn.
In your default.aspx.cs code, you're simply pointing your ButtonTable reference to a different Table control - but you're not affecting the Page.Controls collection. When render time comes, it is the (blank) Table defined in the markup that will be rendered - not the result of your BuildTable call.
All of this is a fairly long winded "you're doing it wrong". The answer to why you want your table building code in a separate class would shed some light on the "right way". But - and I mean no offense - I think you need to study the basics behind ASP.NET before you go any further.
That being said, the most immediate fix (but likely not what you really want) is to add the table to the Controls collection so that it gets rendered:
GetData Buttons = new GetData();//create a reference to the class
ButtonTable = Buttons.BuildTable();
this.Controls.Add(ButtonTable);
OutPut.Text = ButtonTable.Rows.Count.ToString();
Note that it will render separately from your markup defined ButtonTable, and so will be placed after the Output label. That is because it was added after the Output label.
I really suggest you:
Run it line by line in the debugger to see what's going on
Refactor it, the code is hard to read. Adding more comments won't solve that.
Consider what you want to achieve and check if it can fits to databind to a control like ListView.
That said, your code:
GetData Buttons = new GetData();
ButtonTable = Buttons.BuildTable(); // this is what's wrong
OutPut.Text = ButtonTable.Rows.Count.ToString();
Just assigning the control in the page it's not the way to do it. Either add the returned table to the controls collection, or change BuildTable to receive the table it will load the info into. Never directly assign to the control of the asp.net page, once I had to debug code with some very strange issues and a developer had assigned null to a control (not to a property of the control) which messed up during the asp.net render cycle.
ButtonTable = Buttons.BuildTable();
What do you do in there here?