How to dynamically create controls in asp.net aspx file - c#

I am having difficulty adding a Button control to a specific spot in an .aspx page. I think I can create the button, but I don't know how to add it to the page.
Code is as follows:
<%
var cpus = productItems.FindAll(t => t.Type == "cpu");
foreach (var cpu in cpus)
{ %>
<div class="row product cpu">
<div class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%= cpu.Price %></span>
<span class="addtocart">
<% Button b = new Button();
b.ID = "Button" + cpu.ID;
b.CommandArgument = cpu.ID.ToString();
b.Text = "Add to Cart";
b.OnClientClick = "Addtocart_Click";
%>
</span>
<br />
</div>
</div>
<% } %>
I can also create the Button as part of the productItems collection, but still presents the problem of how to render the button on the page.
I'm sure there's a better way to do this, just not sure where to look.
Thanks in advance.

In WebForms, you can make use of listing controls that have a concept of a DataSource (Some listing of objects) and a template which renders how each of those objects appear. In general, you should use these whenever you have a list of items that you want to render on the site.
In this particular case, you will probably want to make use of the ListView control. This allows you to define a layout template and an item template.
Your aspx markup would look like the following:
<asp:ListView ID="lvCpus" OnItemDataBound="lvCpus_ItemDataBound" runat="server">
<LayoutTemplate>
<div class="row product cpu">
<div runat="server" id="itemPlaceholder"></div>
</div>
</LayoutTemplate>
<ItemTemplate>
<div runat="server" class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%# Eval("Price") %></span>
<span class="addtocart">
<asp:Button ID="addToCart" Text="Add To Cart" runat="server" />
</span>
</div>
</ItemTemplate>
</asp:ListView>
This defines a ListView control and creates a LayoutTemplate that matches your container. Internally it has a div that must have the id itemPlaceholder which is used to populate the various items that are bound to this control.
The ItemTemplate portion defines what you expect each individual item to look like. In this case, it's a column that contains a CPU for purchase.
Notice that the button is defined as a regular ASP Web Control, but none of the dynamic data is set. That's because if you try to assign a property like CommandArgument with an evaluated item, the server tag will not be well-formed and you'll get the YSOD. To work around this, you need to specify an OnItemDataBound function for the ListView that is called when you bind data to this Web Control. In my case, it's called lvCpus_ItemDataBound.
The ItemDataBound method in this case will look like the following:
protected void lvCpus_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
var cpu = e.Item.DataItem as Cpu;
if (cpu == null)
{
return;
}
var btn = e.Item.FindControl("addToCart") as Button;
if (btn == null)
{
return;
}
btn.CommandArgument = cpu.Id.ToString();
// Set other server-side properties required from code.
}
}
When you bind a data source, it has 0 or more items in it. For every item in the data source, this method is called and will let you specify server-side appropriate values that can't be expressed directly in the template.
In our case, we specify the CommandArgument from the Cpu class, but other values could be specified as well.
Finally, we need to make sure we can fill the list view with data. So in Page_Load perhaps, we can bind data to this ListView like the following:
protected void Page_Load(object sender, EventArgs e)
{
lvCpus.DataSource = GetCpus();
lvCpus.DataBind();
}
private IEnumerable<Cpu> GetCpus()
{
yield return new Cpu { Id = 1, Price = 5 };
yield return new Cpu { Id = 2, Price = 10 };
yield return new Cpu { Id = 3, Price = 15 };
yield return new Cpu { Id = 4, Price = 15 };
yield return new Cpu { Id = 5, Price = 20 };
}
We first set the List View's data source to the CPU list that you have and then call the DataBind() method on the ListView. This triggers the OnItemDataBound function to begin filling in the data, and at the end you are left with, in this case, 5 CPUs displayed on the site.

I have added span as runatserver and add control(i.e. button) into it
Try below code,
<div class="row product cpu">
<div class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%= cpu.Price %></span>
<span class="addtocart" id="buttonContainer" runat="server">
<% Button b = new Button();
b.ID = "Button" + cpu.ID;
b.CommandArgument = cpu.ID.ToString();
b.Text = "Add to Cart";
b.OnClientClick = "Addtocart_Click";
buttonContainer.Controls.Add(b);
%>
</span>
<br />
</div>
</div>

In your situation, since you are using inline code, the below approach is the most optimal.
I have place a placeholder control to your original markup, that has an id of placeHolder1 at the location where the button needs to appear. This is what gives you total control over where the button will appear in the rendered page.
You need to use a placeholder control, which is a standard ASP.Net
control for adding controls dynamically at run-time.
You place the placeholder control at the location in your page markup where you would like the dynamically created button to appear.
Then, just use the line of code placeHolder1.Controls.Add(b); to add your button control.
Dynamically add a button at a certain location in your page
<%
var cpus = productItems.FindAll(t => t.Type == "cpu");
foreach (var cpu in cpus)
{ %>
<div class="row product cpu">
<div class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%= cpu.Price %></span>
<span class="addtocart">
<% Button b = new Button();
b.ID = "Button" + cpu.ID;
b.CommandArgument = cpu.ID.ToString();
b.Text = "Add to Cart";
b.OnClientClick = "Addtocart_Click";
placeHolder1.Controls.Add(b);
%>
<asp:PlaceHolder ID="placeHolder1" runat="server"></asp:PlaceHolder>
</span>
<br />
</div>
</div>
<% } %>

Related

How to change the position of divs in asp.net form dynamically

In the design of web form I have four divs
divGeneralDetails
divLanguageDetails
divLinkDetails
divOperationalDetails
Divs mentioned above are displayed vertically in the form.
My question is.
Depending on value in query string, i will have to change the order in which divs are displayed.
In my Page_Load event
string FirstDiv = Request.QueryString["id"];
if value of FirstDiv is equal to "General"
then order should be
- divGeneralDetails
- divLanguageDetails
- divLinkDetails
- divOperationalDetails
if value of FirstDiv is equal to "Operational"
then order should be
- divOperationalDetails
- divGeneralDetails
- divLanguageDetails
- divLinkDetails
How do I set this in Page_Load event. Any help will be highly appreciated.
Thanks
You can use Panel.
Example:
<asp:Panel ID="panelMain" runat="server">
<asp:Panel ID="divGeneralDetails" runat="server"></asp:Panel>
<asp:Panel ID="divLanguageDetails" runat="server"></asp:Panel>
<asp:Panel ID="divLinkDetails" runat="server"></asp:Panel>
<asp:Panel ID="divOperationalDetails" runat="server"></asp:Panel>
</asp:Panel>
And then rearrange it add code behind:
panelMain.Controls.Clear();
panelMain.Controls.Add(divOperationalDetails);
panelMain.Controls.Add(divGeneralDetails);
panelMain.Controls.Add(divLanguageDetails);
panelMain.Controls.Add(divLinkDetails);
If you want to do it server-side, then for good working of ViewState (if it is being used) the Divs would have to be added in the desired order using Page.Controls.Add() in the PreInit event of the Page. Any later may throw off ViewState.
A totally different approach would be to use jQuery in the browser to manipulate the Divs, see the snippet below for one way to achieve this:
function moveOperationalToTop() {
var specialId = "divOperationalDetails";
var $main = $("#divMain");
var $divs = $main.find('div');
$main.empty();
$divs.each(function() {
if (this.id == specialId) $main.append($(this));
});
$divs.each(function() {
if (this.id != specialId) $main.append($(this));
});
}
#divOperationalDetails {
color: red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="divMain">
<div id="divGeneralDetails">divGeneralDetails</div>
<div id="divLanguageDetails">divLanguageDetails</div>
<div id="divLinkDetails">divLinkDetails</div>
<div id="divOperationalDetails">divOperationalDetails</div>
</div>
<button onclick="moveOperationalToTop()">Move Operational to top</button>

How to create and insert HTML at run time?

Would someone give a code example how to create and insert HTML at run time?
The HTML is like this:
<div class="row">
<div class="col-md-3">
<img src="example.png" class="profileImage" /> <br />
<span class="name">Name</span>
<div class="ver"></div>
<img class="flag ver" src="star.png" />
<div class="horizontalBar"></div>
</div>
</div>
The close I get was:
public partial class MyPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.Header.DataBind();
ContentPlaceHolder contents = Page.Master.FindControl("MainContent") as ContentPlaceHolder;
Panel row = new Panel() { CssClass = "row" };
Panel col = new Panel() { CssClass = "col-md-3" };
Image profile = new Image()
{
CssClass = "profileImage",
ImageUrl = "example.jpg"
};
row.Controls.Add(col);
col.Controls.Add(profile);
contents.Controls.Add(row);
}
}
It doesn't work (see below error) and isn't full code, for example, what class is equivalent to generate <span>?
I get this error:
The Controls collection cannot be modified because the control
contains code blocks
What's the reason of that error? which are those code blocks and how do I fix this?
I've tested the code here and it's working.
The control equivalent to span is Label, but I think there must be better ways of doing this.
If you really need to dynamically insert HTML code, you can inject it using the LiteralControl, like this:
var html = new LiteralControl(#"<div class=""row"">
<div class=""col-md-3"">
<img src=""example.png"" class=""profileImage"" />
<br />
<span class=""name"">Name</span>
<div class=""ver""></div>
<img class=""flag ver"" src=""star.png"" />
<div class=""horizontalBar""></div>
</div>
</div>");
contents.Controls.Add(html);

How to bind repeater in loop in c#

I have used repeater in asp.net
<div class="slider-inner">
<div id="daslider" runat="server" class="da-slider">
<asp:Repeater ID="rptSlider" runat="server">
<ItemTemplate>
<asp:Panel ID="sld" runat="server" class="da-slide">
<h2><asp:Literal ID="lblTitle" runat="server"></asp:Literal></h2>
<p>
<asp:Literal ID="lblDescription" runat="server"></asp:Literal>
</p>
<div class="da-img">
<iframe id="framevid" runat="server" visible="false" width="530" height="300" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
<asp:Image ID="sldrimg" runat="server" CssClass="img-responsive"/>
</div>
</asp:Panel>
</ItemTemplate>
<FooterTemplate>
<asp:Panel ID="btnlinks" runat="server" class="da-arrows">
<span class="da-arrows-prev"></span>
<span class="da-arrows-next"></span>
</asp:Panel>
</FooterTemplate>
</asp:Repeater>
</div>
</div>
In CS File I want to bind them programically using loop as below lines of code
private void GetMainAppSettings()
{
MainSetting Item = context.FetchMainAppSettings();
SliderContext contextSlider = new SliderContext();
Slider SW = new Slider();
string PageName = "Home Page";
IEnumerable<_14Muslims.Domain.Entity.Slider> pType = contextSlider.SliderFetchAllEnabled(PageName);
foreach (Slider item in pType)
{
lblTitle.Text = item.SliderTitle;
lblDescription.Text = item.SliderDescription;
framevid.Attributes.Add("src", item.SliderImage);
sldr.Attributes.Add("src", item.SliderImage);
daslider.Style.Add("background-image", WebUtility.UrlSchemeAuthority() + #"/FileStore/AppSettingsSiteLogos/" + item.BackgroundImage);
}
}
Note that GetMainAppSettings() is called on page_load event
Please Help me !!!
There are two separate things that you need to do:
Set the source of the repeater
Tell the repeater what to do for each item in the source.
To achieve the first, you just need to set the DataSource property of the repeater to the collection of items you need displayed, and execute a DataBind call:
private void GetMainAppSettings()
{
MainSetting Item = context.FetchMainAppSettings();
SliderContext contextSlider = new SliderContext();
Slider SW = new Slider();
string PageName = "Home Page";
IEnumerable<_14Muslims.Domain.Entity.Slider> pType = contextSlider.SliderFetchAllEnabled(PageName);
rptSlider.DataSource(pType);
rptSlider.DataBind();
}
When this is done, the repeater will loop through each item, process it and, display whatever is needed. To customize this process, the repeated provides an ItemDataBound event where you can set how the template should look for a specific item:
protected void rptSlider_ItemDataBound(object sender, RepeaterItemEventArgs e) {
// This event is raised for the header, the footer, separators, and items.
// Execute the following logic for Items and Alternating Items.
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
//get the item from the event arguments
var item = (Slider)e.Item.DataItem;
//get the controls
var lblTitle = (Label)e.Item.FindControl("lblTitle");
var lblDescription= (Label)e.Item.FindControl("lblDescription");
var framevid= (HtmlGenericControl)e.Item.FindControl("framevid");
var sldr= (HtmlGenericControl)e.Item.FindControl("sldr");
//set the values
lblTitle.Text = item.SliderTitle;
lblDescription.Text = item.SliderDescription;
framevid.Attributes.Add("src", item.SliderImage);
sldr.Attributes.Add("src", item.SliderImage);
}
}
This will execute once for each item in the data source, and you have complete control over what goes where and how. The looping is done implicitly for you by the repeater itself.
No need to loop the data in your code behind, you can directly assign the DataSource and Repeater control will take care of rest.
In Code behind, you can programatically set the DataSource like this:-
rptSlider.DataSource = pType;
rptSlider.DataBind();
In your repeater control, you can put the Data Binder code nuggets to assign particular properties to control like this:-
<h2><asp:Literal ID="lblTitle" runat="server" Text='<%# SliderTitle%>'></asp:Literal></h2>
and so on..for other controls.
Why use loop for bind repeater? You can directly assign your object "pType" to repeater data source. Like
IEnumerable<_14Muslims.Domain.Entity.Slider> pType = contextSlider.SliderFetchAllEnabled(PageName);
rptSlider.DataSource=pType;
rptSlider.DataBind();
After you can access all your field in repeater on .aspx page.
More Details see below article:
http://www.c-sharpcorner.com/UploadFile/5089e0/how-to-use-repeater-control-in-Asp-Net/

Wrap automatically inserted TextBoxes with HTML in ASP.NET

I want to generate TextBoxes in my ASP.NET webpage. It works fine
foreach (var Field in db.A_Settings)
{
TextBox t = new TextBox();
t.ID = Field.ID.ToString();
t.CssClass = "smallinput";
t.Text = Field.Text;
LabelPlaceHolder.Controls.Add(t);
}
And it nicely generates something like this:
<input name="ctl00$ContentPlaceHolder1$1" type="text" value="ValueA" id="ContentPlaceHolder1_1" class="smallinput">
<input name="ctl00$ContentPlaceHolder1$2" type="text" value="ValueB" id="ContentPlaceHolder1_4" class="smallinput">
<input name="ctl00$ContentPlaceHolder1$3" type="text" value="ValueC" id="ContentPlaceHolder1_5" class="smallinput">
It is correct, but in fact I want to wrap it with some HTML, like
<p>
<label>Label for the first TextBox obtained from database</label>
<span class="field">
<input name="ctl00$ContentPlaceHolder1$1" type="text" value="ValueA" id="ContentPlaceHolder1_1" class="smallinput">
</span>
</p>
I couldn't found how to do it this way, so I was thinking about putting it into List<TextBox>, but I'm stuck here either (the same problem - no idea how to wrap the object with HTML).
Is there any way to do this?
For any posts like "Why don't you add those TextBoxes manually?" I'll send a photo of me hitting my head at keyboard, while there will be a dump of SQL with dozens of fields that needs to be handled displayed on the screen :)Or a photo of a lemur. Lemurs are okay, too
Not the cleanest solution, but should work...
foreach (var Field in db.A_Settings)
{
TextBox t = new TextBox();
t.ID = Field.ID.ToString();
t.CssClass = "smallinput";
t.Text = Field.Text;
//add literal control containing html that should appear before textbox
LabelPlaceHolder.Controls.Add(new LiteralControl("html before"));
LabelPlaceHolder.Controls.Add(t);
//add literal control containing html that should appear after textbox
LabelPlaceHolder.Controls.Add(new LiteralControl("html after"));
}
I would probably use a Repeater control:
<asp:Repeater ID="SettingsRepeater" runat="server">
<ItemTemplate>
<p>
<asp:Label ID="ItemLabel" runat="server"></asp:Label>
<span class="field">
<asp:TextBox ID="ItemTextbox" runat="server"></asp:TextBox>
</span>
</p>
</ItemTemplate>
</asp:Repeater>
And bind the list to the repeater:
SettingsRepeater.DataSource = db.A_Settings;
SettingsRepeater.DataBind();
Then write your ItemDataBound code to set the existing values.
You want HtmlGenericControl controls.
foreach (var Field in db.A_Settings)
{
TextBox t = new TextBox();
t.ID = Field.ID.ToString();
t.CssClass = "smallinput";
t.Text = Field.Text;
var label = new HtmlGenericControl("label");
label.Controls.Add(new LiteralControl("LABEL TEXT"));
var p = new HtmlGenericControl("p");
p.Controls.Add(label);
var span = new HtmlGenericControl("span");
span.Attributes.Add("class", "field");
span.Controls.Add(t);
p.Controls.Add(span);
LabelPlaceHolder.Controls.Add(p);
}
You can create custom ASP.NET Controls that can render any HTML you need. Have a look at this:
Developing a Simple ASP.NET Server Control. This way you can create your a control called CustomTextBox which will render a Textbox inside a paragraph.

User Control is added on postback, but does not display

I have a placeholder control within an UpdatePanel, and when the Add Vehicle button is clicked, I need a new "row" of controls to appear (The first "row" is added declaratively). The UserControl however gets added but not displayed. How can I fix this?
protected void AddVehicleButton_Click(object sender, EventArgs e)
{
int count = Convert.ToInt32(VehicleRegistrationCountHiddenField.Value);
var TBId = "VehicleRegistrationEnhancedTextBox" + count;
IList<Panel> oldPanels = (IList<Panel>)Session["VehiclePanels"] ?? new List<Panel>();
//Seperator
Literal hr = new Literal { Text = "<HR/>" };
//Vehicle Registration
UserControl uc = new UserControl(){ID="3"};
uc.LoadControl("~/Controls/ImageUploadAndCrop/ImageUploadAndCrop.ascx");
Label vehicleRegistration = new Label
{
ID = TBId + "_Label",
AssociatedControlID = TBId,
Text = "Vehicle Registration:"
};
EnhancedTextBox vehicleTypeTextBox = new EnhancedTextBox
{
ID = TBId,
Required = true,
RequiredErrorText = "Vehicle Registration is a required field."
};
//Readd previously added panels
foreach (var addedPanel in oldPanels)
{
AddVehiclePlaceholder.Controls.Add(addedPanel);
}
//Add new controls to the form
Panel newPanel = new Panel();
newPanel.Controls.Add(hr);
newPanel.Controls.Add(uc);
newPanel.Controls.Add(vehicleRegistration);
newPanel.Controls.Add(vehicleTypeTextBox);
AddVehiclePlaceholder.Controls.Add(newPanel);
//Increment the ID count
count++;
VehicleRegistrationCountHiddenField.Value = count.ToString();
//Save the panel to the Session.
oldPanels.Add(newPanel);
Session["VehiclePanels"] = oldPanels;
}
The html is below:
<div id="Step2" style="" data-step="2">
<h2> Step 2 (optional): Capture the offender(s) vehicle Information. </h2>
<hr>
<div id="VehicleTypeFields">
<div>
<label for="">Vehicle Registration</label>
<div id="Body_Body_UpdatePanel1">
<div>
<div>
<script type="text/javascript" src="/Controls/ImageUploadAndCrop/Javascript/jquery.Jcrop.min.js">
<link type="text/css" rel="stylesheet" href="/Controls/ImageUploadAndCrop/CSS/jquery.Jcrop.css">
<script type="text/javascript">
<div>
<div id="Body_Body_VehicleRegistrationImageUploadAndCrop_UploadPanel">
</div>
<input id="Body_Body_VehicleRegistrationEnhancedTextBox" type="text" placeholder="CA123-456" name="ctl00$ctl00$Body$Body$VehicleRegistrationEnhancedTextBox">
</div>
</div>
</div>
</div>
<div id="Body_Body_AddVehiclesUpdatePanel">
<input id="Body_Body_VehicleRegistrationCountHiddenField" type="hidden" value="2" name="ctl00$ctl00$Body$Body$VehicleRegistrationCountHiddenField">
<div>
<hr>
<label id="Body_Body_VehicleRegistrationEnhancedTextBox1_Label" for="Body_Body_VehicleRegistrationEnhancedTextBox1">Vehicle Registration:</label>
<input id="Body_Body_VehicleRegistrationEnhancedTextBox1" type="text" name="ctl00$ctl00$Body$Body$VehicleRegistrationEnhancedTextBox1">
<span id="Body_Body_VehicleRegistrationEnhancedTextBox1_RequiredFieldValidator" style="display:none;">Vehicle Registration is a required field.</span>
</div>
</div>
</div>
The problem is your use of LoadControl on a new instance of UserControl rather than the page's implementation. IE rather than this:
UserControl uc = new UserControl(){ID="3"};
uc.LoadControl("~/Controls/ImageUploadAndCrop/ImageUploadAndCrop.ascx");
Do this instead:
Control uc = LoadControl("~/Controls/ImageUploadAndCrop/ImageUploadAndCrop.ascx");
uc.ID = 3;
I think that will fix your immediate problem with nothing displaying but there are still other issues. While it might be possible to store the entire control in session state, my own testing shows there are anomolies in doing so. I would instead make sure you give each instance of your user control a unique ID (not "3" every time), and store those ID's somewhere. Then loop thru those ID's, calling LoadControl for each one, setting the control ID as you loop (this is required in order for the past viewstate to be reapplied to your user control.
I would also move that loop to either Page_Init or Page_Load so that your dynamically created user controls can properly participate in the page's lifecycle. Creating them in that click event is too late for them to catch their own events and they won't be created at all in the case of a postback outside of that click event.

Categories

Resources