Button Fires Twice - 2 records inserted in Database - c#

Running in MasterPage with AutoEventWireup = true. I cannot change this.
Button inserts new record in database.
When button hits, two records insert.
<asp:Button ID="AddLab" Text="Add Lab" OnClick="AddLab_OnClick" CssClass="btn" runat="server" />
PageDirective:
AutoEventWireup="true" <- I have tried removing this, setting to false.
PageLoad/PreRender show to show you nothing being done here with button:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DbDataReader ddrGrp = rdoGroups();
if (ddrGrp.HasRows)
{
rdoGroup.DataSource = ddrGrp;
rdoGroup.DataBind();
}
ddrGrp.Close();
// preset filter by lab to true
CheckBox FiltLabs = (CheckBox)CommonUI.FindCtrlRecursive(this.Master, "FiltLabs");
FiltLabs.Checked = true;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
// nothing yet
rdoLabs.Items.Clear();
DbDataReader ddrLab = rdoUserLabs();
if (ddrLab.HasRows)
{
rdoLabs.DataSource = ddrLab;
rdoLabs.DataBind();
if (CommonUI.strTest((string)Session["rdoLabs"]))
{
if (Convert.ToInt32(Session["rdoLabs"]) > 0)
{
rdoLabs.SelectedValue = (string)Session["rdoLabs"];
}
}
}
ddrLab.Close();
// get group-lab mappings
cboGroupLab.Items.Clear();
DbDataReader ddrGroupLab = cboGroupLabsMap();
if (ddrGroupLab != null)
{
if (ddrGroupLab.HasRows)
{
cboGroupLab.DataSource = ddrGroupLab;
cboGroupLab.DataBind();
}
}
}
protected void AddLab_OnClick(object sender, EventArgs e)
{
LabAdmn labAdd = new LabAdmn();
TextBox txtLab = (TextBox)CommonUI.FindCtrlRecursive(this.Master, "txtLab");
CheckBox Active = (CheckBox)CommonUI.FindCtrlRecursive(this.Master, "cboLabActive");
string[] strArr = new string[] { "lab_id" };
labAdd.LabName = txtLab.Text;
labAdd.Active = (bool)Active.Checked;
// AddLab is where record is fired...see below...
Hashtable ht = labAdd.AddLab(labAdd, strArr);
ht = labAdd.AddLab(labAdd, strArr);
if (ht != null)
{
HiddenField hLabId = (HiddenField)CommonUI.FindCtrlRecursive(this.Master, "hLabId");
hLabId.Value = Convert.ToString(GetHTParm(ht, strArr[0]));
}
}
#endregion AddLab_OnClick
#region AddLab
public Hashtable AddLab(LabAdmn labAdmn, string[] colOutputNames)
{
DAL myDal = new DAL(DBType, DB);
Hashtable ht = new Hashtable();
DAL.Parameters[] parms = new DAL.Parameters[]
{
new DAL.Parameters("driver_id","A",ParameterDirection.Input),
new DAL.Parameters("lab_id",labAdmn.LabId,ParameterDirection.InputOutput),
new DAL.Parameters("active",labAdmn.Active,ParameterDirection.Input),
new DAL.Parameters("lab_name",labAdmn.LabName,ParameterDirection.Input)
};
CommandType cmdType = CommandType.StoredProcedure;
string cmdText = "asp_Labs_Admin";
ht = myDal.ExecuteQueryOutput(cmdType, cmdText, colOutputNames, parms, true);
return ht;
}
#endregion AddLab
I've read that onclick and runat cause double processing. If I remove runat, the button won't show since it is a server side button. If remove the OnClick event, the event never fires regardless if AutoEventWireup is true, false, or removed.

It looks like you are calling the "AddLab" method twice:
Hashtable ht = labAdd.AddLab(labAdd, strArr);
ht = labAdd.AddLab(labAdd, strArr);

Please look somewhere in your code, if you are not attaching a handler to the button twice. Maybe in the Designer there is an event handler attached. Maybe somewhere in your init code.
Try remove your code with the button and place it again, without the onclick attribute in the markup. add in your page or control into the "oninit" following
AddLab.Click += this.AddLab_OnClick;
But first, try to remove the attribute of the markup and try again, if it still fires twice

Can you rename the AddLab_OnClick() method to something else and assign that in OnClick="" handler? I am thinking AutoEventWireup is triggering the first event and the second one is due to OnClick assignment again..
Also, Try what Luke has suggested. That will prove the event assignments..

Related

List of an object type that prevents backcodes ( like... tbControl.Text = "value" ) from working in asp

I have been working with these properties for a while and have never had this problem before. I have a property like this:
public List<AirlineTickets_DOL> lstAirlineTickets
{
get
{
if (!(ViewState["lstAirlineTickets"] is List<AirlineTickets_DOL>))
{
ViewState["lstAirlineTickets"] = new List<AirlineTickets_DOL>();
}
return (List<AirlineTickets_DOL>)ViewState["lstAirlineTickets"];
}
set
{
ViewState["lstAirlineTickets"] = (List<AirlineTickets_DOL>)value;
}
}
When the data is returned somehow inside the OnTextChanged event I have to fill it in as shown below :
protected void tbFlightNumber_Book_Ticket_TextChanged(object sender, EventArgs e)
{
AutoFillAirlineTicket(sender);
}
private void AutoFillAirlineTicket(object sender)
{
TextBox tbFlightNumber_Book_Ticket = ((Control)sender).NamingContainer.FindControl("tbFlightNumber_Book_Ticket") as TextBox;
TextBox tbFrom_Book_Ticket = ((Control)sender).NamingContainer.FindControl("tbFrom_Book_Ticket") as TextBox;
TextBox tbTo_Book_Ticket = ((Control)sender).NamingContainer.FindControl("tbTo_Book_Ticket") as TextBox;
FillFlightData(tbFlightNumber_Book_Ticket, tbDate_Book_Ticket, tbFrom_Book_Ticket, tbTo_Book_Ticket);
UpdatePanel upAirlineTicket = ((Control)sender).NamingContainer.FindControl("upAirlineTicket") as UpdatePanel;
upAirlineTicket.Update();
//List<AirlineTickets_DOL> lstAirlineTickets = new List<AirlineTickets_DOL>();
lstAirlineTickets.Add(new AirlineTickets_DOL
{
counter = (nCounter > 0 ? nCounter : 1),
FlightNumber = tbFlightNumber_Book_Ticket.Text,
From = tbFrom_Book_Ticket.Text,
To = tbTo_Book_Ticket.Text,
});
nCounter++;
ListView lstviewAirlineTickets = ((Control)sender).NamingContainer.FindControl("lstviewAirlineTickets") as ListView;
lstviewAirlineTickets.DataSource = lstAirlineTickets;
lstviewAirlineTickets.DataBind();
}
When I remove the comment, the FillFlightData function fills the controls (TextBoxes), but when using the property as I explained above, the process of filling the fields does not work and does not give any output on the browser.
If you need more explain just tell me. I will be happy if someone help.
I found the solution, I changed the event to normal onClick Event and make sure the class had to be defined as [Serializable].

How to check a box in CheckedListBox while the items in the list are custom objects in a C# window form application?

I am creating an "export to excel" windows form in c#.
The class contains a CheckedListBox and a "check all" button.
When clicking on the button I want to check all the items in the list in case that at least one checkbox is not checked or uncheck all the checkboxes in case they are all already checked.
I added a small complication, the list of the items is a list of custom objects (see private class inside): "ObjectToExport" class.
public partial class ExcelCustomExportForm : Form
{
private class ObjectToExport
{
private readonly IExcelExportable _form;
public ObjectToExport(IExcelExportable form)
{
_form = form;
}
public override string ToString()
{
return $"{_form.FormName} ({_form.CreatedDate.ToShortDateString()} {_form.CreatedDate.ToShortTimeString()})";
}
}
// each form in the list contains a gridview which will be exported to excel
public ExcelCustomExportForm(List<IExcelExportable> forms)
{
InitializeComponent();
Init(forms);
}
private void Init(List<IExcelExportable> forms)
{
foreach (IExcelExportable form in forms)
{
// Checked List Box creation
FormsCheckedListBox.Items.Add(new ObjectToExport(form));
}
}
private void CheckAllButton_Click(object sender, EventArgs e)
{
// checking if all the items in the list are checked
var isAllChecked = FormsCheckedListBox.Items.OfType<CheckBox>().All(c => c.Checked);
CheckItems(!isAllChecked);
}
private void CheckItems(bool checkAll)
{
if (checkAll)
{
CheckAllButton.Text = "Uncheck All";
}
else
{
CheckAllButton.Text = "Check All";
}
FormsCheckedListBox.CheckedItems.OfType<CheckBox>().ToList().ForEach(c => c.Checked = checkAll);
}
}
The problem is that the following line returns true even if not check box is checked:
var isAllChecked = FormsCheckedListBox.Items.OfType<CheckBox>().All(c => c.Checked);
Similar issue with the following line, if checkAll is true, no check box is checked:
FormsCheckedListBox.CheckedItems.OfType<CheckBox>().ToList().ForEach(c => c.Checked = checkAll);
What is the correct way to fix those two lines of code?
Your Problem begins here.
FormsCheckedListBox.Items.Add(new ObjectToExport(form));
and
var isAllChecked = FormsCheckedListBox.Items.OfType<CheckBox>().All(c => c.Checked);
You are adding instances of 'ObjectToExport' to the FormsCheckedListBox, but while filtering, you are checking filtering with CheckBox.
This means, your filtered query always return empty, and query never reaches All. This can be demonstrated with following example.
var list = new [] { 1,2,3,4};
var result = list.OfType<string>().All(x=> {Console.WriteLine("Inside All"); return false;});
The result of above would be True, and it would never print the "Inside All" text. This is what is happening with your queries.
You can find if any of the checkbox is checked using
var ifAnyChecked = checkedListBox1.CheckedItems.Count !=0;
To change state, you could do the following.
for (int i = 0; i < checkedListBox1.Items.Count; i++)
{
if (checkedListBox1.GetItemCheckState(i) == CheckState.Checked)
{
// Do something
}
}

How can I make the Tapped event of a TextCell open up another page?

I have defined a TextCell like this:
public partial class MyTextCell : TextCell
{
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var item = BindingContext as CategoryGroupWordCountVM;
if (item != null)
{
this.Text = item.Name;
this.Detail = App.DB.GetTotalWordCountBySelectedCategories(item.Id).ToString();
this.StyleId = "disclosure";
}
}
}
I added an add a tapped event like this:
section = new TableSection("Select from Available Categories");
foreach (var category in categoryGroups)
{
var cell = new CategoryGroupTextCell { BindingContext = category };
cell.Tapped += openCategoriesPage();
section.Add(cell);
}
}
tableView.Root.Add(section);
I have an openCategoriesPage method:
async void openCategoriesPage(object sender, ItemTappedEventArgs e)
{
if (e.Item == null) return;
var categoriesPage = new CategoriesPage();
var categoryGroup = e.Item as CategoryGroupWordCountVM;
((ListView)sender).SelectedItem = null;
await Navigation.PushAsync(categoriesPage);
}
However I have a problem in that I get an error saying that:
CategoryGroupPage.xaml.cs(36,36): Error CS7036: There is no argument
given that corresponds to the required formal parameter 'sender' of
'CategoryGroupPage.openCategoriesPage(object, ItemTappedEventArgs)'
Can someone advise me if I am doing the opening of the next page correctly and also what could be the cause of my error?
You should subscribe to the Tapped event with the method name alone (without the parentheses), like this:
cell.Tapped += openCategoriesPage;
It's the same as doing the following:
cell.Tapped += new EventHandler(openCategoriesPage);
The compiler will generate the same IL code for both but the first one makes more sense if you want to unsubscribe from the event handler in the future (which you most likely will).

Get html of div in codebehind ASP.NET c# [duplicate]

<form runat="server" id="f1">
<div runat="server" id="d">
grid view:
<asp:GridView runat="server" ID="g">
</asp:GridView>
</div>
<asp:TextBox runat="server" ID="t" TextMode="MultiLine" Rows="20" Columns="50"></asp:TextBox>
</form>
Code behind:
public partial class ScriptTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
g.DataSource = new string[] { "a", "b", "c" };
g.DataBind();
TextWriter tw = new StringWriter();
HtmlTextWriter h = new HtmlTextWriter(tw);
d.RenderControl(h);
t.Text = tw.ToString();
}
}
Even the GridView is within a from tag with runat="server", still I am getting this error.
Any clues please ?
You are calling GridView.RenderControl(htmlTextWriter), hence the page raises an exception that a Server-Control was rendered outside of a Form.
You could avoid this execption by overriding VerifyRenderingInServerForm
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. */
}
See here and here.
An alternative to overriding VerifyRenderingInServerForm is to remove the grid from the controls collection while you do the render, and then add it back when you are finished before the page loads. This is helpful if you want to have some generic helper method to get grid html because you don't have to remember to add the override.
Control parent = grid.Parent;
int GridIndex = 0;
if (parent != null)
{
GridIndex = parent.Controls.IndexOf(grid);
parent.Controls.Remove(grid);
}
grid.RenderControl(hw);
if (parent != null)
{
parent.Controls.AddAt(GridIndex, grid);
}
Another alternative to avoid the override is to do this:
grid.RenderBeginTag(hw);
grid.HeaderRow.RenderControl(hw);
foreach (GridViewRow row in grid.Rows)
{
row.RenderControl(hw);
}
grid.FooterRow.RenderControl(hw);
grid.RenderEndTag(hw);
Just after your Page_Load add this:
public override void VerifyRenderingInServerForm(Control control)
{
//base.VerifyRenderingInServerForm(control);
}
Note that I don't do anything in the function.
EDIT: Tim answered the same thing. :)
You can also find the answer Here
Just want to add another way of doing this. I've seen multiple people on various related threads ask if you can use VerifyRenderingInServerForm without adding it to the parent page.
You actually can do this but it's a bit of a bodge.
First off create a new Page class which looks something like the following:
public partial class NoRenderPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{ }
public override void VerifyRenderingInServerForm(Control control)
{
//Allows for printing
}
public override bool EnableEventValidation
{
get { return false; }
set { /*Do nothing*/ }
}
}
Does not need to have an .ASPX associated with it.
Then in the control you wish to render you can do something like the following.
StringWriter tw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(tw);
var page = new NoRenderPage();
page.DesignerInitialize();
var form = new HtmlForm();
page.Controls.Add(form);
form.Controls.Add(pnl);
controlToRender.RenderControl(hw);
Now you've got your original control rendered as HTML. If you need to, add the control back into it's original position. You now have the HTML rendered, the page as normal and no changes to the page itself.
Here is My Code
protected void btnExcel_Click(object sender, ImageClickEventArgs e)
{
if (gvDetail.Rows.Count > 0)
{
System.IO.StringWriter stringWrite1 = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite1 = new HtmlTextWriter(stringWrite1);
gvDetail.RenderControl(htmlWrite1);
gvDetail.AllowPaging = false;
Search();
sh.ExportToExcel(gvDetail, "Report");
}
}
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. */
}
Tim Schmelter's answer helped me a lot, but I had to do one more thing to get it to work on my aspx page. I am using this code to email an embedded GridView control (as HTML), for report automation.
In addition to adding the override sub, I had to do the render() in Me.Handles.onunload, or else I got an error on the RenderControl line.
Protected Sub Page_After_load(sender As Object, e As EventArgs) Handles Me.Unload
If runningScheduledReport Then
Dim stringBuilder As StringBuilder = New StringBuilder()
Dim stringWriter As System.IO.StringWriter = New System.IO.StringWriter(stringBuilder)
Dim htmlWriter As HtmlTextWriter = New HtmlTextWriter(stringWriter)
GridView1.RenderControl(htmlWriter)
Dim htmlcode As String = stringBuilder.ToString()
Func.SendEmail(Context.Request.QueryString("email").ToString, htmlcode, "Auto Report - Agent Efficiency", Nothing)
End If
End Sub

How to loop through the div to reset the delegate of the links in?

If i have method like this to Draw my side Menu Dynamically :
private void DrawSideMenu()
{
LinkButton x;
TaskDTO TaskList = new TaskDTO();
List<TaskDTO> List = TaskList.DrawMenu(int.Parse(Session["emp"].ToString()));
HtmlGenericControl myDIV = new HtmlGenericControl("div");
myDIV.ID = "menu8";
HtmlGenericControl myOrderedList = new HtmlGenericControl("ul");//css clss for <ul>
myOrderedList.ID = "orderedList";
myOrderedList.Attributes.Add("class", "task");
HtmlGenericControl listItem1;
string count = "";
foreach (TaskDTO i in List)
{
count = AdjustMenuCount1(i.TaskCode);
x = new LinkButton();
x.ID = i.TaskCode.ToString();
x.Text = i.TaskName + " " + count;
x.Click += new EventHandler(TaskC);
x.Style["FONT-FAMILY"] = "tahoma";
listItem1 = new HtmlGenericControl("li");
listItem1.Attributes.Add("class", "normal");
if (count != "0")
{
listItem1.Controls.Add(x);
myOrderedList.Controls.Add(listItem1);
}
}
myDIV.Controls.Add(myOrderedList);
MenuTD.Controls.Add(myDIV);
Session["SideMenu"] = myDIV;//Save to redraw when page postbacks
}
This Method takes long time to draw my menu.so i call it one time in (!IsPostBack) and save it in session so that i could redraw it like that :
MenuTD.Controls.Add( ((System.Web.UI.Control)(Session["SideMenu"])));
It redraws it successfully but when i click on any link it doesn't hit the event because i thought it's not possible to save the x.Click += new EventHandler(TaskC); in the session ,so i want to know how to loop through my session content to resetting the delegate of my link ?
That idea won't work because if you're not wiring up the Event Handler every time the page is loaded, it won't run.
If we come back to the original issue, you said it's slow. Creating controls at runtime cannot be slow and it's most likely the way you create your list of items:
List<TaskDTO> List = TaskList.DrawMenu(int.Parse(Session["emp"].ToString()));
Instead of storing complete menu, try to store in the Session only List and create all controls as usual. If menu is required on one page only, then use ViewState instead of Session.
Also it makes sense to change the entire code as currently you hardcode all style and layout settings in the code. Create all layout (div, ul, li) in aspx, move all styles in css (for example, you use "task" class but still set "tahoma" in the code). This would simplify the code and bring more flexibility.
List<TaskDTO> List = null;
void Page_Load(object sender, EventArgs e)
{
if (ViewState["List"] != null) {
List = (List<TaskDTO>)ViewState["List"];
} else {
// ArrayList isn't in view state, so we need to load it from scratch.
List = TaskList.DrawMenu(int.Parse(Session["emp"].ToString()));
}
// Code to create menu, e.g.
if (!Page.IsPosBack) {
Repeater1.DataSource = List;
Repeater1.DataBind();
}
}
void Page_PreRender(object sender, EventArgs e)
{
// Save PageArrayList before the page is rendered.
ViewState.Add("List", List);
}
...
<ul id="orderedList">
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<li><%# Eval("TaskName") %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
Maybe save it in application level so it only gets built once, then just put the menu into an object and loop through it to re-add the clicks.
I'm afraid that in order for it to work you are going to have to rebind the Click handler on every Page_Load.
Based on your code, and assuming your TaskC is available, you can make this method:
private void RebindMenuHandlers() {
if(Session["SideMenu"] == null)
return; // Your menu has not been built yet
var menu = ((System.Web.UI.Control)(Session["SideMenu"]));
var orderedList = menu.Controls[0];
foreach(var listItem in orderedList){
foreach(var control in listItem){
var linkButton = control as LinkButton;
if(linkButton != null){
linkButton.Click += new EventHandler(TaskC);
}
}
}
}
Then call it on your Page_Load event:
void Page_Load(object sender, EventArgs e)
{
RebindMenuHandlers();
// .... etc
}
I just typed this directly here, so please forgive any silly compilation mistakes, this should be enough to give you the general idea. Hope that helps.

Categories