I have created a user control that is a textbox with some validation which I am adding dynamically to a grid. The grid's data source is from a dataset.
Because of this I am looping through my grid and loading the control to specific cells in the grid where I want them to be.
The problem I have is because I am adding this control dynamically, this somehow stops the validation from working.
User Control
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="TextboxPercentage.ascx.cs"
Inherits="tesco.User_Controls.TextboxPercentage" %>
<%# register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="cc2" %>
<div id="percentage">
<asp:TextBox runat="server" ID="txtPercentage" Width="40" onfocus="if (this.value=='0') this.value='';" onblur="if
(this.value=='') this.value='0';" Text="0"></asp:TextBox>
<asp:Label runat="server" ID="lbl1">%</asp:Label>
<asp:RegularExpressionValidator ID="Reg_percentage" ControlToValidate="txtPercentage"
runat="server" ErrorMessage="Numbers with 18 digits and two decimal values only. eg.9999999.99"
Display="None" ValidationExpression="\b\d{1,18}\.?\d{0,2}" Enabled="true"></asp:RegularExpressionValidator>
<asp:RangeValidator ID="rval_percentage" ControlToValidate="txtPercentage" MinimumValue="0"
MaximumValue="100" Type="Double" runat="server" ErrorMessage="Numbers between 0-100 only" Display="None" ></asp:RangeValidator>
<cc2:ValidatorCalloutExtender ID="vce_percentage_value" runat="server" TargetControlID="Reg_percentage"
Enabled="True">
</cc2:ValidatorCalloutExtender>
<cc2:ValidatorCalloutExtender ID="vce_percentage_range" runat="server" TargetControlID="rval_percentage"
Enabled="True">
</cc2:ValidatorCalloutExtender>
Code behind
GridView1.DataSource = ds;
GridView1.DataBind();
AssignCellCoordinates();
private void AssignCellCoordinates()
{
// Create IDs for Grid
for (int i = 0; i < GridView1.Rows.Count; i++)
{
GridView1.Rows[i].ID = "r" + i; // Row ID
for (int ii = 0; ii < GridView1.Rows[i].Cells.Count; ii++)
{
GridView1.Rows[i].Cells[ii].ID = "c" + ii; // Cell ID
if (GridView1.Rows[i].ID == "r25" || GridView1.Rows[i].ID == "r26" || GridView1.Rows[i].ID == "r27")
{
if (GridView1.Rows[i].Cells[ii].ID != "c0")
{
User_Controls.TextboxPercentage txtPerc = (User_Controls.TextboxPercentage)LoadControl("~/User_Controls/TextboxPercentage.ascx");
GridView1.Rows[i].Cells[ii].Controls.Add(txtPerc);
}
}
}
}
}
As you can see I loop through a row and for each row iteration I add cell IDs until I reach total cells for one row. Within my inner loop I add the control if its certain cell id. But my validation doesn't work.
Anyone have ideas why this is?
Thanks
Dynamically created controls are lost on every postback. I would recommend adding the usercontol to your markup to prevent following scenarios:
People often run into problems with there usercontrols not showing.
Usercontrols events not getting fired, because the usercontrols do not exist in the markup instead are dynamically generated.
There is no difference in the speed(page-size). You can toggle there visibility according to your needs.
Much cleaner, elegant solution.
Anyways if you really need adding table dynamically, have a look at this question Dynamic Controls and Postback and this tutorial https://web.archive.org/web/20210330142645/http://www.4guysfromrolla.com/articles/092904-1.aspx
Related
I'm trying to create a quiz in web application in asp.net C# using a database. The quiz has 25 question and 5 answers and each answer has a number of points(totally agree(1),agree(2), not sure(3), disagree(4), totally disagree(5)).
The questions and answers are in a database.
What I want is when i click on the submit button to calculate the score from those questions and put the score in a table from my database.
I try to do a if (radiobutton1.checked){
score=2}
but it doesn't work because of the repeater...I guess i'm not sure.
I try to delete the repeater but when i done that the questions and answers do not display on the web page.
In my aspx file i write code to display my data from database like that(using a repeater and table):
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<table>
<tr>
<td> <%#Eval("IDq") %> ) <%#Eval("qustion") %></td></tr>
<tr>
<td>
<asp:RadioButton ID="RadioButton1" runat="server" Text='<%#Eval("ans1")%>' GroupName="quiz" Value="1"></asp:RadioButton>
<asp:RadioButton ID="RadioButton2" runat="server" Text='<%#Eval("ans2") %>' GroupName="quiz" Value="2"></asp:RadioButton>
<asp:RadioButton ID="RadioButton3" runat="server" Text='<%#Eval("an3") %>' GroupName="quiz" Value="3"></asp:RadioButton>
<asp:RadioButton ID="RadioButton4" runat="server" Text='<%#Eval("ans4") %>' GroupName="quiz" Value="4"></asp:RadioButton>
<asp:RadioButton ID="RadioButton5" runat="server" Text='<%#Eval("ans5") %>' GroupName="quiz" Value="5"></asp:RadioButton>
<br />
</td>
</tr> </table>
</ItemTemplate></asp:Repeater>
Ok, you have a good start.
And I am going to suggest that in place of the RadioGroup tag?
That DOES get you automatic ONLY one choice. The problem is we STILL will have to check all 5 controls.
A better control in this case to use what is called a RadioButtonList. It works VERY much like having used RadioGroup, but the REALLY nice part?
It is ONE control, and if there are 3 or 15 choices for Radio button group, it as ONE control returns
the index of the selection (0 to N)
the text value of the selection
the value value of the selection.
So I recommend using a RadioButton list - since it is "one thing" that returns the selections.
The "major" problem with the RadioButtonList is you CAN'T use those cool data bound expresisons ike you are using now (that was a good call/design on your part).
However, either we write a loop to "get/check" the 5 raido buttons, or we write a loop to fill the Radiobutton list - I think using code to fill out the RadioButton list is a better choice.
Also, you new - and I see you are attempting to use some "table and "tr" to help you lay out things. You don't really need this.
Now, because ALL of the above ideas saves us so much time, so much code? Well, then we can add extra code to say
show the score and results after we submit
tell the user they did NOT answer a question - they MUST!!!
heck, toss is a cool check box, or X box to show wrong or right.
Allow a question to only have say 2 answers - not always all 5
Ok first up, our table - it looks like this:
So, we have the IDq (id of question). The 1 to 5 possible answers, and then a column with the CORRECT answer.
Ok, now our markup. As I stated, since we reduced so much markup and code, then I added the message in big bold red that appears when a user did not answer all questions.
And I also added a "results" box that shows when you hit submit (number wrong, and correct).
So, now our Markup becomes like this:
<div style="width:35%">
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<div style="float:left">
<asp:Label ID="Question" runat="server"
Text = '<%# Eval("IDq").ToString + " ) " + Eval("question") %>'
Font-Size="X-Large">
</asp:Label>
</div>
<div style="float:right">
<img id="MyImage" runat="server" src="" height="48" width="48" />
</div>
<div style="clear:both">
<asp:RadioButtonList ID="RadioButtonList1" runat="server" RepeatDirection="Horizontal" ></asp:RadioButtonList>
</div>
<br />
<hr></hr>
</ItemTemplate>
</asp:Repeater>
<asp:Button ID="cmdDone" runat="server" Text="Submit" />
<div id="MyError" style="display:none;normal;color:red" runat="server">
<h2>You have not answered all questions</h2>
<h2>Please answer all questions before submitting</h2>
</div>
<div id="Results" runat="server" style="clear:both; display:none" >
<h2>Results</h2>
<asp:TextBox ID="MyCorrect" runat="server"></asp:TextBox>
<br />
<asp:TextBox ID="InCorrect" runat="server"></asp:TextBox>
</div>
</div>
so, not a lot of markup - and we added quite a bit new features.
I also tossed in the idea to show a check box for correct, and wrong - you can remove that part - but it does help you learn a lot here.
So, now when I run the code, I see this:
So note the questions I have correct. As I stated - you may well want to remove that.
And note the message that I not yet answered all questions.
So, as noted, we have a LITTLE bit more code to load up the Repeater, but less to check things after.
So, our code now looks like this:
private DataTable MyTable = new DataTable();
protected void Page_Load(object sender, System.EventArgs e)
{
if (IsPostBack == false)
{
LoadData();
ViewState["MyTable"] = MyTable;
}
else
MyTable = ViewState["MyTable"];
}
public void LoadData()
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT * from tblQuestions ORDER BY IDq",
new SqlConnection(My.Settings.TEST4)))
{
cmdSQL.Connection.Open();
MyTable.Load(cmdSQL.ExecuteReader);
Repeater1.DataSource = MyTable;
Repeater1.DataBind();
}
}
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{
DataRow MyRow = MyTable.Rows(e.Item.ItemIndex);
RadioButtonList rBtnList = e.Item.FindControl("RadioButtonList1");
for (var i = 1; i <= 5; i++)
{
var strR = "ans" + i;
if (IsDBNull(MyRow(strR)) == false)
{
ListItem nItem = new ListItem(MyRow(strR), i);
rBtnList.Items.Add(nItem);
}
}
}
}
protected void cmdDone_Click(object sender, EventArgs e)
{
// check all rows - make sure all have a answer
// show check box for correct answers
// total up correct answers (count)
// total up wrong answers (count)
MyError.Style("Display") = "none";
int Correct = 0;
int Wrong = 0;
int NotAnser = 0;
foreach (RepeaterItem ritem in Repeater1.Items)
{
RadioButtonList RadioBut = ritem.FindControl("RadioButtonList1");
if (RadioBut.SelectedIndex >= 0)
{
HtmlImage MyImage = ritem.FindControl("MyImage");
if (MyTable.Rows(ritem.ItemIndex).Item("Answer") == RadioBut.SelectedIndex + 1)
{
Correct += 1;
MyImage.Src = "/Content/ok.png";
}
else
{
Wrong += 1;
MyImage.Src = "/Content/reject.png";
}
}
else
{
NotAnser += 1;
}
}
// if missed questions then display warning.
if (NotAnser > 0)
MyError.Style("Display") = "normal";
else
{
MyCorrect.Text = "Correct answers = " + Correct;
InCorrect.Text = "Wrong answers = " + Wrong;
Results.Style("Display") = "normal";
}
}
So you can see in that submit button code, we are NOW with great ease to loop the repeater, get the user answer, check against the table data.
And note the other trick - I persist MyTable into ViewState. I did this since I did not want to have to re-load the table each time - it just means for ANY button click, control and code behind? I ALWAYS have the data table at my fingertips
Now, given the above does total up the answer, then you would have to add 2-5 more lines of code to write out the total, or the results - it not clear if you plan to have some other table where you have say some student ID, or user id, and you save the total results of the test (or the correct count, or wrong count).
so, the final result looks like this:
I'm not really proficient in asp.net. I Have a asp based web application and I want to create a custom GridView in order to use it whenever I have a search box and reduce redundancy in my code.
I want to have this GridView below my textbox and on text changing the GridView shows mostly searched results and a "More" button for advance search which will open a new page. Can anybody help me how can I start?
Thanks.
Here a small example of how you could achieve this. First add the necessary items needed to do a search to the aspx page. Note that the buttons have an OnCommand so that you can send a CommandName along with them.
<asp:TextBox ID="SearchField" runat="server" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ErrorMessage="A search term is required" ValidationGroup="Search"
ControlToValidate="SearchField">
</asp:RequiredFieldValidator>
<asp:Button ID="SearchButton" runat="server" Text="Search"
OnCommand="DoSearch_Command" CommandName="Search" ValidationGroup="Search" />
<asp:GridView ID="SearchResultsGridView" runat="server" AutoGenerateColumns="true"></asp:GridView>
<asp:Button ID="MoreButton" runat="server" Text="More"
OnCommand="DoSearch_Command" CommandName="More"/>
Now in the code behind you process the button clicks of Search and More. I created some dummy data with a List, but you need to replace that with the correct data source that holds your search results (List, DataTable etc).
protected void DoSearch_Command(object sender, CommandEventArgs e)
{
//create a new item to hold search results, in this case a list
List<string> searchResults = new List<string>();
//the text from the textbox that contains the search word
string searchTerm = SearchField.Text.Trim();
//hide the 'more' button
MoreButton.Visible = false;
//add some dummy data for testing
for (int i = 1; i <= 50; i++)
{
searchResults.Add("Search result " + i);
}
//if the results are more than 10 and the click is not from the 'more' button take 10 items
if (searchResults.Count > 10 && e.CommandName == "Search")
{
searchResults = searchResults.Take(10).ToList();
//show the more button
MoreButton.Visible = true;
}
//show results in gridview
SearchResultsGridView.DataSource = searchResults;
SearchResultsGridView.DataBind();
}
Is there any way where we can reproduce the content of a panel.For example i have a panel which has two text box .On clicking more button i would like to have another panel below which again has two text box like the first one or add two text box into the existing panel.My end goal is to add controls as the user clicks on more button and get data from those controls .This is the controls inside the panel that i would like to reproduce
any possible way where i can add the controls as shown in the layout through server side ?Please help!
There are plenty ways to solve this. You could add proper DOM elements by yourself using plain JavaScript or jQuery, or use some JS MV* frameworks, like KnockoutJS (example: http://knockoutjs.com/examples/contactsEditor.html) or AngularJS.
you can obviously add dynamic controls from code behind on button click event of 'more button'.
Click Here for more references:
If you want to achieve this on client side using jQuery, then 'closest()' (to find the source element/row to be repeated nearby to the add/remove button etc., especially if it is in a tabular/grid format) in conjunction with 'clone()' function, (to make a copy of the source element/row) and then you can paste the clone inside the target container.
The following link might help you achieve what you want:
jQuery Clone table row
But doing this in Asp.Net WebForms should be much straight forward.
Also, please be noted that, it would always be much helpful to get a quicker answer by specifying more details(eg., MVC, WebForms etc. in the description, what trials you did to find/fix the problem) and that help save other's time as well. For more info: https://stackoverflow.com/questions/how-to-ask
try this
your aspx page add
<asp:TextBox runat="server" ID="TextBox1" />
<asp:TextBox runat="server" ID="TextBox2" />
<asp:Button Text="Add" ID="btnAdd" OnClick="btnAdd_Click" runat="server" />
<asp:Repeater ID="rpt" runat="server">
<ItemTemplate>
<asp:TextBox runat="server" ID="txt1" Text='<%# Eval("str1") %>' />
<asp:TextBox runat="server" ID="txt2" Text='<%# Eval("str2") %>' /><br />
</ItemTemplate>
</asp:Repeater>
and in code behind
protected void btnAdd_Click(object sender, EventArgs e)
{
List<temp> lst = GetItemFromRpt();
lst.Add(new temp
{
str1=TextBox1.Text,
str2 = TextBox2.Text
});
rpt.DataSource = lst;
rpt.DataBind();
}
private List<temp> GetItemFromRpt()
{
List<temp> lst = new List<temp>();
for (int i = 0; i < rpt.Items.Count; i++)
{
temp obj = new temp();
obj.str1 = ((TextBox)rpt.Items[i].FindControl("txt1")).Text;
obj.str2 = ((TextBox)rpt.Items[i].FindControl("txt2")).Text;
lst.Add(obj);
}
return lst;
}
public class temp // instead of temp you can use whatever your entity class you need
{
public string str1 { get; set; }
public string str2 { get; set; }
}
I hope I can explain this properly.
I have a grid that is part of our 3rd party shopping cart software. This grid has a row of quantity text boxes into which the customer enters how many of each thing they want to buy.
I put this grid inside a panel so I can set it on or off with
myPanel.Visible=true;
I also have a button to show and one to hide using the above code method.
If I enter a value into a textbox and then click the hide button and then click the show button, when the panel reappears the values are zero. If I then reload the page (browser reload) then the value returns as it was originally. It's a pretty good magic trick but not what I need. What am I doing wrong?
Eventually I want to select a date from a calendar while it is hidden but that is not in play yet... just the show/hide buttons.
Thanks
This sounds like the correct behaviour of ASP.NET WebForms and ViewState
First page load: Panel is visible and the panel loaded with its initial values.
Hide Panel: As soon as the button is pressed a post back occurs. myPanel is set to invisible which on the server side means that the HTML for the panel is not generated (this can be confirmed by looking the generated HTML).
Show Panel: A post back occurs again. But because the values were not rendered in the previous step, they are not available in the ViewState to repopulate the panel.
Reload of the page: This start the process over again (Same as step 1)
A possible solution is to instead hide the panel (<div) on the client-side. This will also have the benefit of not making a round trip to the server to just enable/disable the panel.
Your code should be like below...
Show and Hide button definition to show/Hide the panel is in Java script. That mans there is no handler of Button click event at server side...This approach is suggested normally and fast..
Sample ASPX Code
<script type="text/javascript" language="javascript">
function Hide() {
var ID = document.getElementById('pnl');
ID.style.display = 'none';
return false;
}
function Show() {
var ID = document.getElementById('btnHide');
ID.style.display = 'block';
return false;
}
</script>
<asp:panel id="pnl" runat="server">
<asp:GridView ID="grd" runat="server">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Label ID="ed" runat="server" Text='<%#Eval("name") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</asp:panel>
<asp:button text="Hide" runat="server" id="Button1" onclientclick="return Hide();" />
<asp:button text="Show" runat="server" id="btnShow" onclientclick="return Show();" />
Sample Code Behind
public partial class Default4 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
using (DataTable Dt = new DataTable())
{
using (DataColumn Dc = new DataColumn("Name"))
{
Dt.Columns.Add(Dc);
DataRow dr = Dt.NewRow();
dr["name"] = "1";
Dt.Rows.Add(dr);
dr = Dt.NewRow();
dr["name"] = "2";
Dt.Rows.Add(dr);
grd.DataSource = Dt;
grd.DataBind();
}
}
}
}
}
I have a standard ASP.NET GridView and I'd like the first column (a emplateField) to be rendered as <th>, or in ASP.NET terms, I'd like to set it to the GridView RowHeaderColumn property. But that property is looking for the name of a DataItem (from a BoundColumn).
How can I render my TemplateField with <th> tags?
Finally found a workaround for this. I am not sure if this code has anything to do with good ASP.NET practices, but it does the trick:
public class FirstColumnHeaderGridView : GridView
{
protected override void InitializeRow(GridViewRow row, DataControlField[] fields)
{
DataControlFieldCell cell = new DataControlFieldHeaderCell(fields[0]);
DataControlCellType header = DataControlCellType.DataCell;
fields[0].InitializeCell(cell, header, row.RowState, row.RowIndex);
row.Cells.Add(cell);
DataControlField[] newFields = new DataControlField[fields.Length - 1];
for (int i = 1; i < fields.Length; i++)
{
newFields[i - 1] = fields[i];
}
base.InitializeRow(row, newFields);
}
}
Let me explain what is going on here. We are creating a special type of GridView, that will render its first column using <th> tags no matter how this column is created. For this we are overriding the InitializeRow method. This method basically configures cells for the row. We are handling the first cell, and let standard GridView take care of the rest.
The configuration we are applying to the cell is fully taken from the GridView implementation and is enough for the cell to be rendered with <th> tag instead of <td>.
After that workaround the usage is absolutely standard - register our class as a server control and use it as usual GridView:
<%# Register Assembly="WebApplication1" Namespace="WebApplication1" TagPrefix="wa1" %>
...
<wa1:FirstColumnHeaderGridView ID="Grid1" runat="server" ...>
<Columns>
<asp:TemplateField>
<ItemTemplate>
Will be inside th
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
Will be inside td
</ItemTemplate>
</asp:TemplateField>
</Columns>
</wa1:FirstColumnHeaderGridView>
Is this what you mean?
<Columns>
<asp:TemplateField HeaderText="Código" ItemStyle-Width="9%">
<HeaderTemplate>
<asp:Label runat="server" Text="CodigoSAP"></asp:Label>
</HeaderTemplate>
<ItemTemplate>
<asp:Label runat="server" ID="lblCodigoSAP" Text='<%# Bind("CodigoSAP") %>'> </asp:Label>
</ItemTemplate>
</asp:TemplateField>
I'm almost sure I'm getting the wrong idea, what do you say?
Late to the game, but we needed to set scope="row" in a middle column, not the first. To make it generic, in a derived GridView class I added the following property (similar to the GridView's built-in RowHeaderColumn property):
public int? RowHeaderColumnIndex
{
get { return (int?)ViewState["RowHeaderColumnIndex"]; }
set { ViewState["RowHeaderColumnIndex"] = value; }
}
Then set the scope:
protected override void OnRowCreated(GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow && RowHeaderColumnIndex.HasValue)
{
e.Row.Cells[RowHeaderColumnIndex.Value].Attributes["scope"] = "row";
}
}
When you place your custom grid just set RowHeaderColumnIndex="0" for the first column, "1" for the 2nd column and so on.