Accessing multiple values from generated panel - c#

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);

Related

Why do controls delete when copying controls from one panel to the next

I created a template panel to go by when my form loads that holds a record. When adding a new record I have a method that duplicates that template panel and then adds it to my list of panels for each record. Somehow controls are getting deleted from my template panel when I am duplicating it and I have no idea how this is happening. The portion of code doing this is listed below
Panel pn = new Panel()
{
Width = _PNTemp.Width,
Height = _PNTemp.Height,
Left = 0,
Top = 0,
BackColor = _PNTemp.BackColor,
ForeColor = _PNTemp.ForeColor,
AutoScroll = true,
Name = _PNTemp.Name,
Tag = _PrgPanels.Count.ToString()
};
MessageBox.Show(_PNTemp.Controls.Count.ToString());
foreach (Control c in _PNTemp.Controls)
{
pn.Controls.Add(c);
MessageBox.Show(_PNTemp.Controls.Count.ToString());
}
MessageBox.Show(_PNTemp.Controls.Count.ToString());
_PrgPanels.Add(pn);
I put the messagebox.show() in at 3 points to narrow down where it is happening. The first one shows the correct number of controls, the second and third shows a 1/2 the total amount of controls. why is this?
This is because each control can be added to only one parent control. All controls in your template panel are already a child of the template panel. When you try to add these controls to a new panel, the controls will get removed from the template panel.
As per the docs:
A Control can only be assigned to one Control.ControlCollection at a
time. If the Control is already a child of another control it is
removed from that control before it is added to another control.
Which means that you need to create new controls instead of adding those in the template.
An alternative approach is to create a method that returns the template panel. When you need the template panel, just call the method and a new panel will be created:
public static Panel CreateTemplatePanel() {
Panel pn = new Panel();
// set properties, add controls...
return pn;
}
A control can only be on one panel at once. I've added comments inline in your code to help explain whats happening.
Panel pn = new Panel()
{
Width = _PNTemp.Width,
Height = _PNTemp.Height,
Left = 0,
Top = 0,
BackColor = _PNTemp.BackColor,
ForeColor = _PNTemp.ForeColor,
AutoScroll = true,
Name = _PNTemp.Name,
Tag = _PrgPanels.Count.ToString()
};
MessageBox.Show(_PNTemp.Controls.Count.ToString());
//all the controls are still inside _PNTemp
foreach (Control c in _PNTemp.Controls)
{
pn.Controls.Add(c);
MessageBox.Show(_PNTemp.Controls.Count.ToString());
//Each time this runs you remove a control from _PNTemp to pn.
}
//All the controls moved from _PnTemp to pn
MessageBox.Show(_PNTemp.Controls.Count.ToString());
_PrgPanels.Add(pn);

Using a User control as dynamic control (may be a literal control) in C# asp.net

I have a user control which is an image button.
I want that control to be dynamically added "n" times in my webpage.
"n" comes from the database.
I tried this code:
in "aspx":
<%# Register TagPrefix="uc" TagName="imgbtn" Src="~/components/seatfromdb/usercontrol/UC_imgbutton.ascx" %>
.........................................
//some code goes here
.......................................
<uc:imgbtn ID="uc_imgbtn"
runat="server"
/>
in "cs":
for(int i=0;i<5;i++)
{
UserControl uc = new UserControl();
uc = uc_imgbtn;
//uc.Attributes.Keys = "~/images/buttonorange.png";
//uc.ID = "uc" + i.ToString();
//uc.Height = 30;
plhdr_seat.Controls.Add(uc);
plhdr_seat.Controls.Add(new LiteralControl("<br />"));
}
But the control "uc" added to the page only one time. Why?
Please help me with this code.
Do not create UserControl, call Page.LoadControl method to get a new instance of UC_imgbutton.
for(int i = 0; i < 5; i++)
{
UC_imgbutton uc = (UC_imgbutton)LoadControl("~/components/seatfromdb/usercontrol/UC_imgbutton.ascx");
//uc.Attributes.Keys = "~/images/buttonorange.png";
//uc.ID = "uc" + i.ToString();
//uc.Height = 30;
plhdr_seat.Controls.Add(uc);
plhdr_seat.Controls.Add(new LiteralControl("<br />"));
}
This happens because you are always assigning uc_imgbtn to your new UserControl();. In other words you are always assign the same existing control to the plhdr_seat.Controls collection.
Check the Note at this link for more details:
A Control can only be assigned to one Control.ControlCollection at a
time. If the Control is already a child of another control it is
removed from that control before it is added to another control.
If you want to add a new uc_imgbtn control every time to the plhdr_seat.Controls collection you should change your code to:
UserControl uc = new UserControl(); // change this
uc = uc_imgbtn; // remove this
In the first line you must make sure sure you properly initialize the uc control. As far as I can see from your code, this should work: imgbtn uc = new imgbtn();

find dynamically added controls from container

I am generating dynamic textbox controls on drop down selected index change event.
protected void ddlCategories_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (Attributes attribute in getAllAttributes(Convert.ToInt32(ddlCategories.SelectedValue)))
{
Panel div = new Panel();
div.Attributes.Add("class", "form-group");
HtmlGenericControl lbl = new HtmlGenericControl("label");
lbl.Attributes.Add("class", "col-lg-2 control-label");
lbl.InnerText = attribute.Name;
Panel innerdiv = new Panel();
innerdiv.Attributes.Add("class", "col-lg-10");
TextBox txt = new TextBox();
txt.ID = attribute.ID.ToString();
txt.Attributes.Add("class", "form-control");
innerdiv.Controls.Add(txt);
div.Controls.Add(lbl);
div.Controls.Add(innerdiv);
CustomAttributes.Controls.Add(div);
}
}
Now after the user fill up the values in the form i want to get the values of the dynamically generated controls. But CustomAttributes.findControls("") doesn't work for me. it gives null all the time.
I also tried
var textBoxesInContainer = CustomAttributes.Controls.OfType<TextBox>();
but it also doesnt work.
Can any one please tell me what is going wrong here.
Thanks
Finally i found the reason after googling the issue. The issue in this question is a view state.
In asp.net when the page post back it loses the viewstate for the dynamically generated controls. So to get over this issue i recreated the controls in the page load event when it is post back. in that way controls will be added back to the current page and i can find those controls in the button on click event.
thanks all for your time and guidence.
Panel div = new Panel();
Panel innerdiv = new Panel();
TextBox txt = new TextBox();
innerdiv.Controls.Add(txt);
div.Controls.Add(innerdiv);
CustomAttributes.Controls.Add(div);
Your CustomAttributes holds Panel.
Try this :
var textboxes = CustomAttributes.Controls.OfType<Panel>()
.Select(p => p.Controls.OfType<Panel>().First())
.Select(p => p.Controls.OfType<TextBox>().First())

How to use a Variable or Function to declare my SqlDataSource ID in HTML

I'm writing a for loop that displays a list of links with some chartfx display. The chartfx needs an sqlDataSource. I'm trying to give the unique ID each time the for loop does one iteration but I can not pass it a value or function. Example below in my code.
getSQLID() is just a function that returns a string which I want to be my ID. This is all done on the aspx page and the function is in the .cs . Any help would be really appreciated thank you.
//name of the contentplace holder on the aspx page
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server" >
//code behind
Control ctrl = LoadControl("WebUserControl.ascx");
Control placeHolderControl = this.FindControl("Content2");
Control placeHolderControl2 = this.FindControl("ContentPlaceHolder1");
ctrl.ID = "something";
if (placeHolderControl != null)
placeHolderControl.Controls.Add(ctrl);
if (placeHolderControl2 != null)
placeHolderControl2.Controls.Add(ctrl);
First of all, recall that server controls declared in the designer like this are attached to your class at compile time. So it doesn't make sense to try to create multiple instances in a loop at runtime, and that's why the values in e.g. the Id tag have to be known at compile time.
One alternative is to create them in the code behind, with something like:
for (int i=0; i<2; ++i)
{
var chart = new Chart();
chart.Id = "chartId" + i;
chart.DataSourceId = "srcid" + i;
var src = new SqlDataSource();
src.Id = "srcid" + i;
Controls.Add(chart); // either add to the collection or add as a child of a placeholder
Controls.Add(src);
}
In your case converting all of those declarative properties to the code behind can be a bit of work (though it is possible). An alternative is to make a user control (ascx) that contains the markup that's now in your aspx page. You would instantiate the controls in your code behind with something like:
for (int i=0; i<2; ++i)
{
var ctrl = LoadControl("~/path/to/Control.ascx");
ctrl.Id = "something_" + i;
Controls.Add(ctrl); // again, either here or as a child of another control
// make the src, hook them up
}

Custom Header in GridView

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.

Categories