First time posting here, so if something doesn't fit, just let me know. Also I'm not very experienced with ASP and C#, so if I just overlooked something obvious, I'm sorry.
The problem:
In the Page_Load, I call my own class MyGridViewExtension. In the constructor of this class, a Gridview will be created. The catch is: In the Headers of this Gridview is not only a Literal, but also a Listbox. The use of these Listboxes is the filtering of the displayed data, which is achieved by marking one (or more, but that doesn't matter) options of the Listbox and then clicking a button for the postback.
I tried to work with the SelectedIndexChanged Event, but that only fires AFTER the Page_Load is already completed, and as my constructor is called in it, after my GridView has already been created.
//this is the selectedIndexChanged Event Handler
private void AddToFilterList(Object sender, EventArgs e){
ListBox source=sender as ListBox;
string attributeName=source.Parent.ID; //get column name
List<string> filterList=new List<string>();
foreach(ListItem singleFilter in Source.Items){
if(singleFilter.Selected==true){
filterList.Add(singleFilter.Text);
}
}
}
//This works
The problem is, that the Constructor will complete before AddToFilterList even gets called, and afterwards it doesn't help anymore, as I need the filterList when in the constructor.
As for other code, it looks somewhat like this:
public Class MyGridViewExtension(Array Data){
checkForSelectedOptions(); //how can I have my filterList here already?
List<string> columnNames=getAllColumnNamesByCheckingData(Data);
//-create the template field to show the data
foreach (string col in columnNames)
{
TemplateField tfield = new TemplateField();
//In here, the listboxes are created
tfield.HeaderTemplate = new GridViewTemplate(ListItemType.Header, col, this);
tfield.ItemTemplate = new GridViewTemplate(ListItemType.Item, col, this);
this.Columns.Add(tfield);
}
this.DataSource=Data; //I actually transform the array to a datatable before, but that shouldn't matter here
}
protected void Page_Load(object sender, EventArgs e){
Array data=getDataFromWebserver(); //works
MyGridViewExtension thisNewGridView=new MyGridViewExtension(data);
thisNewGridView.DataBind();
divName.Controls.Add(thisNewGridView); //add the gridview to a div on the page
}
Everything works fine, getting data and displaying it, but what blocks me is that I just can't get the selected Items of the Listboxes (the filterList variable) into the Constructor.
EDIT: I should probably add that I should hold the code in the page_load as small as possible, as my job is only the Extension class and every entry in the page_load has to be made (every time) when my class is called, which should be kept to a minimum.
Thanks in advance for potential answers, comments (and edits, as my post probably isn't as good as I hope it to be).
I already edited heavily, because I overlooked something important; sorry for all those who already tried to understand/answer.
LAST EDIT: I somewhat solved the problem by re-enabling ViewState for the entire GridView, which causes some overriding problems. But those were easier to deal with than the problem described here, so that is probably the better route.
Thanks to everybody who gave tips.
protected void Page_Load(object sender, EventArgs e)
{
Array data;
if (IsPostback)
{
data = Session["data"] == null ? getDataFromWebserver() : Session["data"] // if session is null, go get data, otherwise use session variable.
}
else
{
// Go get you data, since it is a first load or a refresh
// once you have data - put it in session
Session["data"] = getDataFromWebserver();
data = Session["data"];
}
MyGridViewExtension thisNewGridView=new MyGridViewExtension(data);
thisNewGridView.DataBind();
divName.Controls.Add(thisNewGridView); //add the gridview to a div on the page
// No you can do whatever you need to do...
// some code
}
try this, see if it helps.
This works. It loads a dropdown list from which you may select an item, upon which data is filtered. This is what you are describing or at least the way I understand it. Dropdown maybe substituted for your listboxes, however, I think ddl's are cleaner looking (personal preference though).
Code-behind:
using xxx.DB;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace xxx_Internal_SQL.PostTree.Reports.FailedLeads
{
public partial class Default : System.Web.UI.Page
{
private string programName = "Post_Reports_FailedLeads";
private List<string> lstTransactionSource = new List<string>();
private List<string> lstTransactionSubSource = new List<string>();
private List<string> lstTransactionRef = new List<string>();
private List<string> lstTransactionSubRef = new List<string>();
private List<string> lstIsTest = new List<string>();
private string TransactionSource = string.Empty;
private string TransactionSubSource = string.Empty;
private string TransactionRef = string.Empty;
private string TransactionSubRef = string.Empty;
private string IsTest = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (IsPostBack)
{
if (Session["myDataView"] != null)
BindDataToGV((DataView)Session["myDataView"]);
}
else
{
FillDDL();
ViewState["sortOrder"] = "";
Session["OriginalDT"] = null;
}
}
catch (Exception ex)
{
Global.ReportProblem(ex, programName, "Page_Load");
}
}
private void FillTable(string sortExp, string sortDir)
{
try
{
ClearGV();
object myData;
DataTable dtData = GetData();
Session["OriginalDT"] = dtData;
if (sortExp != string.Empty)
{
DataView myDataView = new DataView();
myDataView = dtData.AsDataView();
myDataView.Sort = string.Format("{0} {1}", sortExp, sortDir);
dtData = myDataView.ToTable();
Session["OriginalDT"] = dtData;
Session["myDataView"] = myDataView;
myData = myDataView;
}
BindDataToGV(dtData);
}
catch (Exception ex)
{
Global.ReportProblem(ex, programName, "FillTable");
}
}
private DataTable GetData()
{
return GetData(db, values);
}
private void ClearGV()
{
gvTransactions.DataSource = null;
gvTransactions.DataBind();
}
private void BindDataToGV(object obj)
{
gvTransactions.DataSource = obj;
gvTransactions.DataBind();
}
private DataTable GetData(Database db, SortedList<string, string> values)
{
DataTable dt = null;
try
{
if (db.GenericSP("sp_xxx", values, true))
return db.Output_DT;
}
catch (Exception ex)
{
Global.ReportProblem(ex, programName, "GetData");
}
return dt;
}
protected void lnkFindTransactions_Click(object sender, EventArgs e)
{
try
{
if (ddlAffiliates.SelectedIndex > 0) FillTable("", "");
}
catch (Exception ex)
{
Global.ReportProblem(ex, programName, "lnkFindTransactions_Click");
}
}
protected void gvTransactions_Sorting(object sender, GridViewSortEventArgs e)
{
FillTable(e.SortExpression, sortOrder);
}
protected void gvTransactions_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvTransactions.PageIndex = e.NewPageIndex;
if (Session["OriginalDT"] != null)
BindDataToGV((DataTable)Session["OriginalDT"]);
}
public string sortOrder
{
get
{
if (ViewState["sortOrder"].ToString() == "desc")
{
ViewState["sortOrder"] = "asc";
}
else
{
ViewState["sortOrder"] = "desc";
}
return ViewState["sortOrder"].ToString();
}
set
{
ViewState["sortOrder"] = value;
}
}
private void FillDDL()
{
if (db.GetRecords("sp_xxx"))
{
DataTable dt = db.Output_DT;
ddlAffiliates.Items.Add(new ListItem("Select...", ""));
foreach (DataRow dr in dt.Rows)
ddlAffiliates.Items.Add(new ListItem(dr["name"].ToString(), dr["aid"].ToString()));
}
}
}
}
front-end:
<asp:Table runat="server">
<asp:TableRow>
<asp:TableCell Width="100px" HorizontalAlign="Right">Date: </asp:TableCell>
<asp:TableCell Width="200px" HorizontalAlign="Left">
<ajaxToolkit:CalendarExtender runat="server" Animated="true"
ID="extCalendarEnd" TargetControlID="txtDateEnd">
</ajaxToolkit:CalendarExtender>
<asp:TextBox ID="txtDateEnd" runat="server" Width="180px"></asp:TextBox>
</asp:TableCell>
<asp:TableCell Width="75px" HorizontalAlign="Left">Seller: </asp:TableCell>
<asp:TableCell Width="200px" HorizontalAlign="Left">
<asp:DropDownList ID="ddlAffiliates" runat="server" Enabled="false"></asp:DropDownList>
</asp:TableCell>
<asp:TableCell HorizontalAlign="Left">
<asp:UpdatePanel runat="server" UpdateMode="Always" ID="upnlFind" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:LinkButton ID="lnkFindTransactions" runat="server" CssClass="linkButton" OnClick="lnkFindTransactions_Click" Text="Find" />
</ContentTemplate>
</asp:UpdatePanel>
</asp:TableCell>
</asp:TableRow>
<asp:TableRow>
<asp:TableCell ColumnSpan="5">
<hr />
<asp:Panel runat="server" Width="600px" Height="100%">
<asp:Panel runat="server" ID="pnlGridview" Width="500px" Style="margin: 0px auto 0px auto;">
<asp:GridView runat="server" ID="gvTransactions"
GridLines="None" AllowPaging="True"
AllowSorting="True" PageSize="25"
CellPadding="4" ForeColor="#333333"
Width="600px" OnSorting="gvTransactions_Sorting"
OnPageIndexChanging="gvTransactions_PageIndexChanging"
RowStyle-Wrap="false" CssClass="gvTransactions">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<PagerSettings Position="TopAndBottom" Mode="NumericFirstLast" />
<PagerStyle HorizontalAlign="Left" />
<EditRowStyle BackColor="#999999" />
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#E9E7E2" />
<SortedAscendingHeaderStyle BackColor="#506C8C" />
<SortedDescendingCellStyle BackColor="#FFFDF8" />
<SortedDescendingHeaderStyle BackColor="#6F8DAE" />
</asp:GridView>
</asp:Panel>
</asp:Panel>
</asp:TableCell>
</asp:TableRow>
</asp:Table>
as a closing note. It is not a perfect all addressing code, but it does what it was designed to do. Feel free to build on-top of it or modify any part of it.
Related
I'm seeing this behavior on two of my pages, but I'm just going to ask about the one that's more important to me at the moment. I have a page that loads information from a database into a ASP gridview and then allows the user to add a detail to each populated line.
The issue I'm having is that when the 'Edit' button of the gridview and then subsequently the 'Update' or 'Cancel' button, it takes two click to actually fire the onclick event. A post back does take place on the first click, but nothing actually happens.
I'm including the code that seems relevant below. The page uses a master page and there are a number of divs involved with formatting, I'm excluding those.
Gridview and related controls:
<asp:UpdatePanel runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label Text="Plant Selector: " runat="server" />
<asp:DropDownList ID="ddlPlant" OnSelectedIndexChanged="ddlPlant_SelectedIndexChanged" runat="server" />
<asp:Button ID="btnUpdate" Text="Update" OnClick="btnUpdate_Click" runat="server" />
<p />
<asp:Label ID="lblTest" Text="" runat="server" />
<asp:Label ID="lblerror" Text="" ForeColor="Red" runat="server" />
<asp:GridView ID="gridview1" AutoGenerateColumns="false" runat="server" OnRowEditing="gridview1_RowEditing" OnRowCancelingEdit="gridview1_RowCancelingEdit" OnRowUpdating="gridview1_RowUpdating">
<Columns>
<asp:BoundField DataField="JobNum" HeaderText="Job Number" ReadOnly="true" />
<asp:BoundField DataField="ModelNum" HeaderText="Model" ReadOnly="true" />
<asp:BoundField DataField="Customer" HeaderText="Customer" ReadOnly="true" />
<asp:BoundField DataField="SchCompDate" HeaderText="Sch Comp Date" ReadOnly="true" />
<asp:TemplateField HeaderText="Details">
<EditItemTemplate>
<asp:TextBox ID="Txt" Width="98%" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label Text="Click Edit to add details of exception." runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowEditButton="true" />
</Columns>
</asp:GridView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="gridview1" />
</Triggers>
</asp:UpdatePanel>
Sample image below:
Here is the code behind:
private string Plant { get; set; }
// This sets the default plant based off IP.
protected void Page_PreInit(Object sender, EventArgs e)
{
getPlantFromIP();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
populateDDL();
BindData();
}
else
{
Plant = ddlPlant.SelectedValue.ToString();
}
}
// Populates the drop down.
private void populateDDL()
{
ddlPlant.Items.Add("NC");
ddlPlant.Items.Add("WA");
setPlantInDDL();
}
private void setPlantInDDL()
{
if(Plant == "WA")
{
ddlPlant.SelectedIndex = 1;
}
if (Plant == "NC")
{
ddlPlant.SelectedIndex = 0;
}
}
private void getPlantFromIP()
{
if (Request.ServerVariables["REMOTE_ADDR"] == "70.103.118.100")
{
Plant = "WA";
//ddlPlant.SelectedIndex = 1;
}
else
{
Plant = "NC";
//ddlPlant.SelectedIndex = 0;
}
}
// Database Query.
private DataTable getDataFromDatabase()
{
DataTable rTable = new DataTable();
string plant = ddlPlant.SelectedValue.ToString();
using (var conn = new MySqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["workorderConnectionString"].ConnectionString))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
try
{
cmd.CommandText = #"SELECT * FROM reportdatatables.compliance_exception_report
WHERE ExceptionNoted = '0' AND Plant = #plant";
cmd.Parameters.AddWithValue("#plant", plant);
MySqlDataReader reader = cmd.ExecuteReader();
rTable.Load(reader);
reader.Close();
cmd.Dispose();
}
catch
{
}
finally
{
conn.Close();
}
}
}
return rTable;
}
// Binds the data from the database to the gridview.
private void BindData()
{
DataTable data = getDataFromDatabase().Copy();
gridview1.DataSource = data;
gridview1.DataBind();
}
protected void ddlPlant_SelectedIndexChanged(object sender, EventArgs e)
{
//Plant = ddlPlant.SelectedValue.ToString();
BindData();
}
// On edit call.
protected void gridview1_RowEditing(object sender, GridViewEditEventArgs e)
{
}
// On cancel call.
protected void gridview1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
gridview1.EditIndex = -1;
}
protected void gridview1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
}
protected void btnUpdate_Click(object sender, EventArgs e)
{
BindData();
}
Here's what I've tried:
-A lot of posts a read saw this behavior relating to autopostback settings of controls. As you can see I'm made sure to not have any control with the autopostback set to true.
-I had some concern that the behavior might be related to the updatepanel, but removing it doesn't change the behavior at all.
-I read that having AutoEventWireup="true" in your page tag can cause this. I DO have that in my page tag, but setting it to false does not fix the issue and prevents my dropdown from being populated on page load.
-There was another post that suggested the ID of the control could be changing between page load and post back. I monitored the IDs of those controls and I do not see any change in their ID.
So all that being said, I'm hoping someone has a clue as to what I'm missing. If there is any more information I can provide that might help, please let me know.
Thank you in advance.
Try this, which will make the grid editable
protected void gridview1_RowEditing(object sender, GridViewEditEventArgs e)
{
GridView1.EditIndex = e.NewEditIndex;
BindData();
}
for cancel also
protected void gridview1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
gridview1.EditIndex = -1;
BindData();
}
I have an ASP.NET website where I have to show some data on a Gridview, I need this data to be shown as fast as possible, so I decided to create a timer inside an Update panel and then Refresh the grid over and over, however I see that my timer is not waiting until it was done in order to Tick again, it's executing itself over and over, which is giving me performance issues on the database, how can I tell my timer "hey stop until this process is done, then continue".
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Timer ID="Timer1" runat="server" Interval="400" OnTick="Timer1_Tick" EnableViewState="False">
</asp:Timer>
<asp:GridView ID="gv_stats" runat="server" AutoGenerateColumns="False" BackColor="White" BorderColor="#999999" BorderStyle="Solid" BorderWidth="1px" CellPadding="3" ForeColor="Black" ShowHeaderWhenEmpty="True" GridLines="Vertical" Width="562px" OnRowDataBound="gv_stats_RowDataBound" ShowFooter="True" EnableViewState="False" >
<AlternatingRowStyle BackColor="#CCCCCC" />
<Columns>
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
I tried this:
private bool is_refreshing = false;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
}
}
protected void Timer1_Tick(object sender, EventArgs e)
{
Timer1.Enabled = false;
if(is_refreshing == false)
BindGrid();
Timer1.Enabled = true;
}
public void BindGrid()
{
is_refreshing = true;
grd.datasource = con.executedt;
grd.databind();
is_refreshing = false;
}
When you refresh the grid, you can set a private boolean variable indicating the that the grid is refreshing and before the execution of code that refreshes the grid, you can check this variable.
EDIT - Try using a session variable instead of a private variable. See updated example.
Example -
// code change starts
private bool _isGridRefreshing
{
get
{
var flag = HttpContext.Current.Session["IsGridSession"];
if(flag != null)
{
return (bool)flag;
}
return false;
}
set
{
HttpContext.Current.Session["IsGridSession"] = value;
}
}
// code change ends
protected void Timer1_Tick(object sender, EventArgs e)
{
if(_isGridRefreshing == false)
{
RefreshGrid();
}
}
private void RefreshGrid()
{
_isGridRefreshing = true;
//code to refresh the grid.
}
Note - I haven't tested the code, but it should give a fair idea of what needs to be done.
I have a gridview with some data and I want to add a checkbox column which can choose multiple rows. By clicking on it I want to save an primary key of row and change css class of row.
Using this article(step 2) I created itemtemplate,added there a checkbox(specifying ID as TransactionSelector), and add a checkedChange() to it. There I only change a css class of row and add a row index to arraylist. But when I click button with event which show this list, it has no items.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="TransactionSelector" runat="server"
oncheckedchanged="TransactionSelector_CheckedChanged" AutoPostBack="True" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="iTransactionsId" HeaderText="iTransactionsId"
SortExpression="iTransactionsId" />
<asp:BoundField DataField="mAmount" HeaderText="mAmount"
SortExpression="mAmount" />
<asp:BoundField DataField="vchTransactionType" HeaderText="vchTransactionType"
SortExpression="vchTransactionType" />
<asp:BoundField DataField="dtDate" HeaderText="dtDate"
SortExpression="dtDate" />
<asp:BoundField DataField="cStatus" HeaderText="cStatus"
SortExpression="cStatus" />
<asp:BoundField DataField="test123" HeaderText="test123"
SortExpression="test123" />
</Columns>
<RowStyle CssClass="unselectedRow" />
</asp:GridView>
</asp:Panel>
<asp:Panel ID="InfoPanel" runat="server" CssClass="infoPanel">
<asp:Button ID="ShowSelected" runat="server" Text="Button"
onclick="ShowSelected_Click" />
<asp:Label ID="InfoLabel" runat="server"></asp:Label>
</asp:Panel>
C Sharp code:
public partial class WebForm1 : System.Web.UI.Page
{
ArrayList indices = new ArrayList();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GridView1.DataSourceID = "SqlDataSource1";
GridView1.DataBind();
}
}
protected void TransactionSelector_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
GridViewRow row = (GridViewRow)cb.NamingContainer;
// row.CssClass = (cb.Checked) ? "selectedRow" : "unselectedRow";
if (cb.Checked)
{
row.CssClass = "selectedRow";
indices.Add(row.RowIndex);
}
else
{
row.CssClass = "unselectedRow";
indices.Remove(row.RowIndex);
}
}
protected void ShowSelected_Click(object sender, EventArgs e)
{
InfoLabel.Text = "";
foreach (int i in indices)
{
InfoLabel.Text += i.ToString() + "<br>";
}
}
}
}
You have to persist variable in postback using ViewState. Also its better if you use List<T> generic implementation rather than ArrayList
ViewState["Indices"] = indices;
And to recover it back
indices = ViewState["Indices"] as ArrayList;
As Habib said, you could use ViewState. You could also use ControlState instead, as shown here. If your code is in a custom control or user control, you may also need to override OnInit to
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.RegisterRequiresControlState(this);
}
Please feel free to respond with feedback. I'm new at posting answers.
The web application that I am developing right now has something called quiz engine which provides users with short quizzes which consist of one question or more. Now, I have a problem with taking/ answering the quiz:
When the user finishes the quiz that consists of 4 questions and he goes to the Result Page and he can go back (using back arrow in the browser) to the Quiz page and answers any question again and this should not be happened and I don't know how to prevent it
For creating the Quiz engine, I used the Toturial for the Quiz Engine in the ASP.NET website for creating what I have.
ASP.NET code:
<tr>
<td>
<asp:DetailsView ID="questionDetails" runat="server" Height="50px" Width="550px" AutoGenerateRows="False" CellPadding="4" DataSourceID="SqlDataSource1" ForeColor="#333333" GridLines="None">
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<CommandRowStyle BackColor="#E2DED6" Font-Bold="True" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" CssClass="generaltext" />
<FieldHeaderStyle BackColor="#E9ECF1" Font-Bold="True" CssClass="boldtext" Width="80px" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<Fields>
<asp:BoundField DataField="Question" HeaderText="Question:" SortExpression="Question" />
<asp:BoundField DataField="Answer1" HeaderText="A:" SortExpression="Answer1" />
<asp:BoundField DataField="Answer2" HeaderText="B:" SortExpression="Answer2" />
<asp:BoundField DataField="Answer3" HeaderText="C:" SortExpression="Answer3" />
<asp:BoundField DataField="Answer4" HeaderText="D:" SortExpression="Answer4" />
</Fields>
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<EditRowStyle BackColor="#999999" />
<AlternatingRowStyle BackColor="White" ForeColor="#284775" CssClass="generaltext" />
</asp:DetailsView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:testConnectionString %>" SelectCommand="SELECT [QuestionID], [Question], [Answer1], [Answer2], [Answer3], [Answer4], [CorrectAnswer], [QuestionOrder] FROM [Question] WHERE ([QuizID] = #QuizID) ORDER BY [QuestionOrder]">
<SelectParameters>
<asp:SessionParameter SessionField="QuizID" Type="Int32" Name="QuizID" DefaultValue="0" />
</SelectParameters>
</asp:SqlDataSource>
</td>
</tr>
<%--<tr>
<td>
</td>
</tr>--%>
<tr>
<td class="boldtext">
<strong>Your Answer:</strong>
<asp:DropDownList ID="answerDropDownList" runat="server">
<asp:ListItem Value="A">A</asp:ListItem>
<asp:ListItem Value="B">B</asp:ListItem>
<asp:ListItem Value="C">C</asp:ListItem>
<asp:ListItem Value="D">D</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
My Code-Behind:
This is the code that is responsible for saving the answers:
protected void Page_Load(object sender, EventArgs e)
{
questionDetails.DataBind();
answerDropDownList.SelectedIndex = 0;
if (questionDetails.PageCount == 1)
{
nextButton.Text = "Finished";
}
}
protected void nextButton_Click(object sender, EventArgs e)
{
// Save off previous answers
System.Data.DataRowView dr = (System.Data.DataRowView)questionDetails.DataItem;
// Create Answer object to save values
Answer a = new Answer();
a.QuestionID = dr["QuestionOrder"].ToString();
a.CorrectAnswer = dr["CorrectAnswer"].ToString();
a.UserAnswer = answerDropDownList.SelectedValue.ToString();
ArrayList al = (ArrayList)Session["AnswerList"];
var oldAnswer = al.ToArray().Where(ans => (ans as Answer).QuestionID == a.QuestionID);
if (oldAnswer.Count() != 0)
{
a = oldAnswer.FirstOrDefault() as Answer;
a.CorrectAnswer = dr["CorrectAnswer"].ToString();
a.UserAnswer = answerDropDownList.SelectedValue.ToString();
}
else
{
al.Add(a);
}
if (questionDetails.PageIndex == questionDetails.PageCount - 1)
{
// Go to evaluate answers
Response.Redirect("Results.aspx");
}
else
{
questionDetails.PageIndex++;
}
if (questionDetails.PageIndex == questionDetails.PageCount - 1)
{
nextButton.Text = "Finished";
}
}
The following code is responsible for saving the result:
protected void Page_Load(object sender, EventArgs e)
{
ArrayList al = (ArrayList)Session["AnswerList"];
if (al == null)
{
Response.Redirect("default.aspx");
}
resultGrid.DataSource = al;
resultGrid.DataBind();
// Save the results into the database.
if (IsPostBack == false)
{
// Calculate score
double questions = al.Count;
double correct = 0.0;
for (int i = 0; i < al.Count; i++)
{
Answer a = (Answer)al[i];
if (a.Result == Answer.ResultValue.Correct)
correct++;
}
double score = (correct / questions) * 100;
string username = HttpContext.Current.User.Identity.Name.ToString().Replace("ARAMCO\\", "");
SqlDataSource userQuizDataSource = new SqlDataSource();
userQuizDataSource.ConnectionString = ConfigurationManager.ConnectionStrings["testConnectionString"].ToString();
userQuizDataSource.InsertCommand = "INSERT INTO [UserQuiz] ([QuizID], [DateTimeComplete], [Score], [Username]) VALUES (#QuizID, #DateTimeComplete, #Score, #Username)";
userQuizDataSource.InsertParameters.Add("QuizID", Session["QuizID"].ToString());
userQuizDataSource.InsertParameters.Add("DateTimeComplete", DateTime.Now.ToString());
// "N4" is for displaying four decimal places, regardless of what the value is
userQuizDataSource.InsertParameters.Add("Score", score.ToString("N4"));
userQuizDataSource.InsertParameters.Add("Username", username);
int rowsAffected = userQuizDataSource.Insert();
if (rowsAffected == 0)
{
// Let's just notify that the insertion didn't
// work, but let' s continue on ...
errorLabel.Text = "There was a problem saving your quiz results into our database. Therefore, the results from this quiz will not be displayed on the list on the main menu.";
}
}
}
protected void resultGrid_SelectedIndexChanged(object sender, EventArgs e)
{
SqlDataSource1.FilterExpression = "QuestionOrder=" + resultGrid.SelectedValue;
}
So now how I can prevent the user from going back to the Quiz when he is in the Result page?
you can use Response.Cache properties to solve this issue .
from MSDN Response. SetAllowResponseInBrowserHistory
When HttpCacheability is set to NoCache or ServerAndNoCache the
Expires HTTP header is by default set to -1; this tells the client not
to cache responses in the History folder, so that when you use the
back/forward buttons the client requests a new version of the response
each time. You can override this behavior by calling the
SetAllowResponseInBrowserHistory method with the allow parameter set
to true.
in your page load method, you add this line .
protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetAllowResponseInBrowserHistory(false);
// or else you can do like this
Response.ExpiresAbsolute = DateTime.Now.AddDays(-1d);
Response.Expires = -1;
Response.CacheControl = "No-cache";
}
I have successfully implemented my GridView now, but, as always, the whole ASP.NET life cycle thing is bothering me. I can't figure out why this doesn't work. I have bound the GridView's OnPageIndexChanged as such:
protected void GridView_PageIndexChanged(object sender, EventArgs e)
{
// Enable/disable the previous/next buttons.
LinkButton btnNextPage = (LinkButton)gvTable.BottomPagerRow.FindControl("btnNextPage");
LinkButton btnPreviousPage = (LinkButton)gvTable.BottomPagerRow.FindControl("btnPreviousPage");
btnNextPage.Enabled = false;
btnPreviousPage.Enabled = false;
}
This is my ASCX:
<asp:GridView ID="gvTable" runat="server" ShowHeader="true" PageSize="1"
AllowPaging="true" AllowSorting="true" DataSourceID="dsLinqActivities"
AutoGenerateColumns="false" OnRowDataBound="GridView_DataBound"
OnPageIndexChanged="GridView_PageIndexChanged">
<Columns>
<asp:BoundField DataField="Edited" HeaderText="Date" />
<asp:BoundField DataField="Status" HeaderText="Status" />
<asp:BoundField DataField="Activity" />
</Columns>
<PagerSettings Position="Bottom" Visible="true" />
<PagerStyle CssClass="pager" />
<PagerTemplate>
<asp:LinkButton ID="btnPreviousPage" class="navbtn prev left"
runat="server" CommandName="Page" CommandArgument="Prev">
<span>Newer activities</span></asp:LinkButton>
<asp:LinkButton ID="btnNextPage" class="navbtn next right"
runat="server" CommandName="Page" CommandArgument="Next">
<span>Older activities</span></asp:LinkButton>
</PagerTemplate>
</asp:GridView>
I debug my application and see that the code is being run and does the right thing but for some reason when the control is rendered, both of the buttons are always enabled. What am I doing wrong here?
If I were you, I would code it like this in the "GridView_PageIndexChanged" method
(gvTable.BottomPagerRow.FindControl("btnNextPage") as LinkButton).Enabled = true/false;
Edit:Can you also try adding a setter ?
set
{
gvTable.BottomPagerRow.FindControl("btnNextPage") as LinkButton =value;
}
Edit: OK my friend, I finally worked out a solution. May be not very elegant,but it works and I tested it. There are a few things to take care of:
1. We are having a "Prev" and a "Next" button and we got to handle "OnCommand" events for those since we are using our own Pager Template
2. We would have to bind data after we handle our OnCommand event.
I have a static List<String> which I populated during GET with random strings (Courtesy: http://www.kivela.be/index.php/2007/06/19/how-to-generate-a-random-string-in-c-20/) and bound them to my grid. You can substitute your own datasource here.Also, we have to change the grid's page index manually in our OnCommand Event.
Here is my aspx/ascx grid
<asp:GridView ID="GridView1" runat="server" OnRowDataBound="GridView_DataBound"
AllowPaging="true" PagerSettings-Mode="NextPrevious" PagerSettings-Position="Bottom" PageSize="10"
OnPageIndexChanged="GridView_PageIndexChanged">
<PagerSettings Position="Bottom" Visible="true" />
<PagerStyle CssClass="pager" />
<PagerTemplate>
<asp:LinkButton ID="btnPreviousPage" OnCommand="ChangePage"
runat="server" CommandName="Prev" Text="prev">
</asp:LinkButton>
<asp:LinkButton ID="btnNextPage" OnCommand="ChangePage"
runat="server" CommandName="Next" Text="next">
</asp:LinkButton>
</PagerTemplate>
</asp:GridView>
and here is the codebehind
public partial class TestPage : System.Web.UI.Page
{
private static Random _random = new Random();
static List<string> lst = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
for (int i = 1; i <= 30; i++)
{
lst.Add(RandomString(i));
}
GridView1.DataSource = lst;
GridView1.DataBind();
SetPageNumbers();
}
}
private void SetPageNumbers()
{
if (GridView1.PageIndex == 0)
{
(GridView1.BottomPagerRow.FindControl("btnPreviousPage")as LinkButton).Enabled = false;
}
if(GridView1.PageIndex ==GridView1.PageCount-1)
{
(GridView1.BottomPagerRow.FindControl("btnNextPage") as LinkButton).Enabled = false;
}
}
protected void ChangePage(object sender, CommandEventArgs e)
{
switch (e.CommandName)
{
case "Prev":
GridView1.PageIndex = GridView1.PageIndex - 1;
break;
case "Next":
GridView1.PageIndex = GridView1.PageIndex + 1;
break;
}
GridView1.DataSource = lst;
GridView1.DataBind();
SetPageNumbers();
}
public static string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < size; i++)
{
//26 letters in the alfabet, ascii + 65 for the capital letters
builder.Append(Convert.ToChar(Convert.ToInt32(Math.Floor(26 * _random.NextDouble() + 65))));
}
return builder.ToString();
}
}
Hope this helps
Is there any chance your CSS is setting the enabled property?
I duplicated your code without the CSS and it works fine for me.
How about posting your css?