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.
Related
I have a user control that has a text box and a button. I have repeated this user control n times using for loop in my main.aspx page
for (int i = 0; i < 5; i++)
{
testcontrol newControl = (testcontrol)LoadControl("~/testcontrol.ascx");
newControl.ID = "myControl-" + i.ToString();
HtmlButton btnGenerateReport =newControl.FindControl("btnGenerateReport") as HtmlButton;
btnGenerateReport.ID = "button_generate-" + i.ToString();
btnGenerateReport.ServerClick += BtnGenerateReport_Click;
}
my testcontrol.ascx looks like this
<div class="row">
<div class="col-md-8 blockMe">
<input runat="server" class="form-control" />
</div>
<div class="col-md-4">
<button type = "button" id="btnGenerateReport" class="btn btn-default btnGenerateReport" aria-label="Left Align" runat="server">
<span class="fa fa-cog" runat="server" id="gennerateReportSpan" aria-hidden="true"></span>
</button>
<br />
</div>
On ButtonClick I am trying to show spinning icon so that i can do some background process. I have subscribed to the HtmlButton OnServerClick method in mainpage.aspx
private async void BtnGenerateReport_Click(object sender, EventArgs e)
{
System.Web.UI.HtmlControls.HtmlControl tt = ((System.Web.UI.Control)sender).Parent.FindControl("gennerateReportSpan") as System.Web.UI.HtmlControls.HtmlControl;
tt.Attributes.Clear();
tt.Attributes.Add("class", "fas fa-spinner fa-spin");
Task taskA = Task.Factory.StartNew(() =>
{
Task.Delay(5000).Wait();
}).ContinueWith((x) =>
{
tt = ((System.Web.UI.Control)sender).Parent.FindControl("gennerateReportSpan") as System.Web.UI.HtmlControls.HtmlControl;
tt.Attributes.Add("class", "fa fa-cog");
});
}
I am trying to achieve the spinning effect by changing the attributes of the htmlelement. I am able to set new class i.e spinning but I am not able to reset it once the task is done. Is there any better way to do it ?
This way you can never make it back to non-spinning because when your thread is finish you don't have no way to inform the client the way you make it.
I can think and suggest two ways
first way - the ajax call
Ok, this is the most common way, to make an ajax call to a aspx file and wait for the return. You can find many example for this...
second way - your way
You make your calculations call inside the page with a flush just before the long running function - when the calculations finish the page will continue to render the rest of it and change back the icon.
Here is a working example.
On aspx page
<form id="form1" runat="server">
<div>
<h1 id="changeme" style="color:blue">Header Test</h1>
</div>
</form>
<%Response.Flush();%>
<%GenerateReport();%>
<script>
document.getElementById("changeme").style.color = "red";
</script>
on page behind
public void GenerateReport()
{
// simulate the delay
Thread.Sleep(5000);
}
Last words
avoid the async on this web pages, is not desktop programming that you don't want to hold the render of the user interface. Here the user is on another computer and the call to you its a new thread by default, a thread to another computer. So all that is done with out any extra new thread creation.
I am using HTML with c#. How i can create new div for each loop in the while to be able to make the designee as i want
my html code:
< div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
<div class="blog-post2">
<div class="post-img"></div>
<div class="post-text">
<div class="date">
<span class="post-date">26</span>
<span class="month">Oct<br>2017</span>
</div>
<h4><a href = "#" > Title </a></h4>
<p>Detelse</p>
detelse
</div></div>
</div>
my C# code:
SqlCommand cmd_check2 = new SqlCommand();
cmd_check2.CommandText = #"SELECT
[title_news]
FROM [website_DB].[dbo].[long_news_T] where id = 1";
//cmd_check.Parameters.AddWithValue("#e_mail", txtUserName.Text);
DataTable df2 = WebTbi_V1._1.func.general.GetData(cmd_check2, Label1, "website");
foreach (DataRow row2 in df2.Rows)
{
//Console.WriteLine("- - - Row - - -");
foreach (var item_1 in row2.ItemArray)
{
my for code ????
}
test.InnerHtml = html;
}
i want create a div for my news depending on result query
i need help
With a little googling you can find many and many samples for this problem
foreach (var item_1 in row2.ItemArray)
{
HtmlGenericControl myDiv = new HtmlGenericControl("div");
myDiv.Attributes.Add("class", "col-lg-4 col-md-4 col-sm-6 col-xs-12");
/*
You need to do same thing for every div you have inside
the parent div, and simply add them to parent div and
finally add your parent div to a Panel or Page or
any other place holder you have
*/
myPanel.Controls.Add(myDiv);
}
You might then need to pay attention for the event, where you generate your controls
You can use text template for it as one of the ways.
Try https://github.com/jehugaleahsa/mustache-sharp for example. Just create HTML template and use {{#each}} tag for loop.
In the future, it will be easier for you to change the template and as for me it's easier to make markupю
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>
<% } %>
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);
I know its a rudimentary questions, but I am out of practice on webforms. I am using Stripe.js for the first time, and want to use it in conjunction with stripe.net to process the client side. Here is the client code:
<%# Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
CodeBehind="StripePage.aspx.cs" Inherits="StripePage.StripePage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
// This identifies your website in the createToken call below
// You need to put your real publish key here.
Stripe.setPublishableKey('pk_test_1nDJ3hA1Mv2Sy9bUoYcBMXmm');
// ...
// I am using jquery to process the payment. It knows what form to
// process it on based on the name 'payment-form'
jQuery(function ($) {
//payment submission
$('#payment-form').submit(function (event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
//if there is a error, it is displayed on the page if there was
//no error this is where it gets sent to the server.
var stripeResponseHandler = function (status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// token contains id, last4, and card type
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
};
});
</script>
<form method="POST" id="paymentForm" runat="server">
<span class="payment-errors" runat="server"></span>
<div class="form-row">
<label>
<span>Card Number</span>
<br />
<input id="number" type="text" data-stripe="number" clientidmode="Static" />
<input type="text" size="20" data-stripe="number" runat="server" />
</label>
</div>
<div class="form-row">
<label>
<span>CVC</span>
<br />
<input type="text" size="4" data-stripe="cvc" runat="server" />
</label>
</div>
<div class="form-row">
<label>
<span>Expiration (MM/YYYY)</span>
<br />
<input type="text" size="2" data-stripe="exp-month" runat="server" />
</label>
<br />
<input type="text" size="4" data-stripe="exp-year" runat="server" />
</div>
<asp:Button ID="submit" ClientIDMode="Static" runat="server" Text="SubmitPayment" OnClick="submit_Click" />
</form>
</asp:Content>
The last call in JS creates a JSON object that I want to know how to get to on the C# page on the button click:
protected void submit_Click(object sender, EventArgs e)
{
....
}
I am wanting to do the javascript implementation to avoid having to do PCI compliance. Am I approaching this incorrectly? Should it be all Stripe.net to process everything, and skip the js entirely? Or if this is right, how can I get the form post data in the button click event?
Thanks for the tips in the comments. After much perusal of the internet and hair pulling, I walked away for a bit and came back with this solution.
Made the button just a standard html input (not the asp:Button)
Got the posted back information that was being sent via the JavaScript in the Page_Load event like so
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
StripeConfiguration.SetApiKey("[API Secret Key");
NameValueCollection nvc = Request.Form;
string amount = nvc["amount"];
var centsArray = amount.Split('.');
int dollarsInCents = Convert.ToInt32(centsArray[0]) * 100;
int remainingCents = Convert.ToInt32(centsArray[1]);
string tokenId = nvc["stripeToken"];
var tokenService = new StripeTokenService();
StripeToken stripeToken = tokenService.Get(tokenId);
var myCharge = new StripeChargeCreateOptions
{
TokenId = tokenId,
AmountInCents = dollarsInCents + remainingCents,
Currency = "usd"
};
var chargeService = new StripeChargeService();
StripeCharge stripeCharge = chargeService.Create(myCharge);
}
}
Seems like using the NameValueCollection (which lives in System.Collections.Specialized namespace) gave me the ability to grab what I needed from the Request.Form by pulling it out via variable name. Since I new the variable names, it was simply a matter of grabbing them and then following the Stripe .NET library documentation to get the token and process the payment.
I want to just post a comment to the answer, but I'm not allowed to yet. So, this isn't really an answer, more of a response to the OP's own findings.
I'm doing the exact same thing, using Stripe.js. I can simply grab stripeToken using Request.Form, and get all other non-c/c-related fields the usual way in the code-behind (e.g. int Total = PaymentTotal.Value;); but what I'm noting isn't so much about grabbing the data, it's that you have to handle it on Page_Load (or during some later point in the page life cycle), because the Submit button's onclick event is never actually fired, since the form is actually submitted using js and not the button.
So, being all literal and kinda answering the original question, you can't actually get the data in the button click event, w/o firing that event manually on postback (I'm surmising).
Hopefully save someone else some time figuring that out if they come here looking to make Stripe and .NET work together.