Custom event firing multiple times - c#

I have an issue similar to the one posted here: Event fires more and more times
However the solution did not work for me. I have a child control that fires an event on button click and a listener on the parent page. When click event occurs and the event is invoked, it fires multiple times on the parent page. Each time incrementing by one.
The page load (on parent) and button click (on child) events only fire once, it is only the event method that runs multiple times.
User Control
public delegate void QuickViewClickEventHandler(int jobId, int bayId);
public static event QuickViewClickEventHandler QuickViewClicked;
protected void QuickViewLinkButton_OnClick(object sender, EventArgs e)
{
// code removed for clarity
OnQuickViewClicked(jobId, bayId);
}
protected void OnQuickViewClicked(int jobId, int bayId)
{
var handler = QuickViewClicked;
if (handler != null)
{
handler(jobId, bayId);
}
}
Parent page
<asp:Repeater runat="server" ID="BayRepeater" OnItemDataBound="BayRepeaterStuff_ItemDataBound">
<ItemTemplate>
<uc:BayViewItem ID="BayViewItemControl" runat="server" />
</ItemTemplate>
</asp:Repeater>
protected void Page_Load(object sender, EventArgs e)
{
BayViewItem.QuickViewClicked += BayViewItem_QuickViewClicked;
}
private void BayViewItem_QuickViewClicked(int jobId, int bayId)
{
// code removed for clarity
// unregistering the event seems to work but only after the first time
// initial page load will still cause it to fire multiple times
BayViewItem.QuickViewClicked -= BayViewItem_QuickViewClicked;
}

Your code looks good. Only after another inspection I see what's going wrong.
In your Page you have an instance of your user control. You should subscribe to that user control's event handler, so it will only be in scope of your page. If you do that you won't risk firing the same event multiple times due to somebody also requesting this page at the same time. There's no reason why the event should be static here and basically making this static causes these issues.
So what you need todo is make your event handler non-static:
public event QuickViewClickEventHandler QuickViewClicked;
Your page your Page_Load should be this where you use the instance of the user control:
protected void Page_Load(object sender, EventArgs e)
{
BayViewItemInstance.QuickViewClicked += BayViewItem_QuickViewClicked;
}
EDIT:
I missed that the control wasn't in the page but in the repeater. So to achieve the same with the repeater (but same can be done in page, without doing it in the Page_Load) is setting the OnQuickViewClicked (On + EventHandler-name) which is the equivalent of .QuickViewClicked += in code-behind:
<asp:Repeater runat="server" ID="BayRepeater" OnItemDataBound="BayRepeaterStuff_ItemDataBound">
<ItemTemplate>
<uc:BayViewItem ID="BayViewItemControl" runat="server" OnQuickViewClicked="BayViewItem_QuickViewClicked" />
</ItemTemplate>
</asp:Repeater>
Now you won't need to unregister anything, since the event handler is not in static scope:
private void BayViewItem_QuickViewClicked(int jobId, int bayId)
{
// code removed for clarity
// unregistering the event seems to work but only after the first time
// initial page load will still cause it to fire multiple times
//BayViewItem.QuickViewClicked -= BayViewItem_QuickViewClicked;
}

Related

Call aspx.cs code fron ascx file

I have a button in ascx file, I want to call a method of my abc.aspx.cs file on clicking this button.
Is there a way to do this from ascx.cs file?
this is my button
<asp:ImageButton ID="ImageButton1" Style="padding-top: 80px; margin-right:10px;" runat="server" ImageUrl="~/App_Themes/Default/Images/Login/NH/DownloadButton.jpg" />
In order to do this in a clean way without coupling the page and the user control, you can create an event in the user control that the parent aspx form subscribes to.
For details on events in C#, see this link.
UserControl.ascx.cs
public class MyUserControl : UserContro
{
public event EventHandler ImageButtonClicked;
private void ImageButton1_Click(object sender, EventArgs e)
{
if (ImageButtonClicked != null) // Check against null as there may not be any subscribers
ImageButtonClicked(this, EventArgs.Empty);
}
// ...
}
WebForm.aspx
<!-- ... -->
<uc:MyUserControl ID="myUserCtrl" runat="server" ImageButtonClicked="myUserCtrl_ImageButtonClicked" />
<!-- ... -->
WebForm.aspx.cs
// ...
private void myUserCtrl_ImageButtonClicked(object sender, EventArgs e)
{
// Call method on page.
}
// ...
Please note that there an be no or many subscribers to the event. If you want to transmit data to the event handler, you need to create your own EventArgs implementation and use an instance of these instead of EventArgs.Empty. This also allows you to check whether the event has been handled by a subscriber, you can add a Handled boolean property to your EventArgs that is set by an event handler and evaluated in the user control afterwards.
There is not such a facility in asp.net But you can use generic handler(.ashx) instead of this
You can define a public method in aspx Page call it using this.Page
((YourASPXPage)(this.Page)).MyMethod();
In ASPX page
public void MyMethod()
{
//Your code
}

Why does my dynamically created user control doesn't fire button click event

i have a problem with user control.
i create it dynamically on my aspx page after clicking on a button:
protected void btnAddRules_Click(object sender, EventArgs e)
{
RuleProperty Control = (RuleProperty)LoadControl("RuleProperty.ascx");
MyPanel.Controls.Add(Control);
}
when i click on a button of my user control, the button event wont fire and the user control will disappear. here is the button event:
protected void btnAdd_Click1(object sender, EventArgs e)
{
WowzaRule rule = GetRuleFromGUI();
RuleList.Add(rule);
//Session["RuleList"] = RuleList;
//List<WowzaRule> test = new List<WowzaRule>();
SaveToXMLFiles(txtdbnum.Text, RuleList);
}
i understand that after pressing the button on mypage the usercontrol is released and if its not created on pag_init or page Load it wont stay, but i need to create it on my button click event and find a way for it not to disapper.
thanks in advance, Daniel
You might have to add an event handler that it can fire the click event and call your delegate
Control.Click += btnAdd_Click1;
Dynamically created controls, once added, have to be on a page on every page load in order to work correctly. What happens in your case:
RuleProperty is added after the button click
Page loads with this control
User clicks on the button within RuleProperty
Control is not added to the control tree during the page load (corresponding code is only in the button click handler, and that button was not clicked)
ASP.NET does not know which control triggered the event, so the event is not processed
To go around this issue you need to add you control on every page loading, for example using some flag stored in ViewState:
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["AddRuleProperty"] != null && (bool)ViewState["AddRuleProperty"])
{
AddRulePropertyControl();
}
}
protected void btnAddRules_Click(object sender, EventArgs e)
{
AddRulePropertyControl();
ViewState["AddRuleProperty"] = true;
}
private void AddRulePropertyControl()
{
RuleProperty Control = (RuleProperty)LoadControl("RuleProperty.ascx");
MyPanel.Controls.Add(Control);
}
Update.
If you want to remove the control from the page later on in the control's click handler, you need to remove corresponding ViewState key. This is not possible from the control directly, since property Page.ViewState is protected, and also this would have created an unwanted dependency.
What seems as the right way to do this is to subscribe to the very same event from the Page (you might need to make this event visible from the controller) and reset the key in there. Like this:
private void AddRulePropertyControl()
{
RuleProperty Control = (RuleProperty)LoadControl("RuleProperty.ascx");
Control.ButtonClick += RuleProperty_ButtonClick;
MyPanel.Controls.Add(Control);
}
private void RuleProperty_ButtonClick()
{
ViewState["AddRuleProperty"] = false;
}
Please note that event name here is not real, this is just a sketch of what can be done.

Dynamically add event to custom control (Confirm Message Box)

I have created a custom cofirm message box control and I created an event like this-
[Category("Action")]
[Description("Raised when the user clicks the button(ok)")]
public event EventHandler Submit;
protected virtual void OnSubmit(EventArgs e) {
if (Submit != null)
Submit(this, e);
}
The Event OnSubmit occurs when user click the OK button on the Confrim Box.
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
OnSubmit(e);
}
Now I am adding this OnSubmit Event Dynamically like this-
In aspx-
<my:ConfirmMessageBox ID="cfmTest" runat="server" ></my:ConfirmMessageBox>
<asp:Button ID="btnCallMsg" runat="server" onclick="btnCallMsg_Click" />
<asp:TextBox ID="txtResult" runat="server" ></asp:TextBox>
In cs-
protected void btnCallMsg_Click(object sender, EventArgs e)
{
cfmTest.Submit += cfmTest_Submit;//Dynamically Add Event
cfmTest.ShowConfirm("Are you sure to Save Data?"); //Show Confirm Message using Custom Control Message Box
}
protected void cfmTest_Submit(object sender, EventArgs e)
{
//..Some Code..
//..
txtResult.Text = "User Confirmed";//I set the text to "User Confrimed" but it's not displayed
txtResult.Focus();//I focus the textbox but I got Error
}
The Error I got is-
System.InvalidOperationException was unhandled by user code
Message="SetFocus can only be called before and during PreRender."
Source="System.Web"
So, when I dynamically add and fire custom control's event, there is an error in Web Control.
If I add event in aspx file like this,
<my:ConfirmMessageBox ID="cfmTest" runat="server" OnSubmit="cfmTest_Submit"></my:ConfirmMessageBox>
There is no error and work fine.
Can anybody help me to add event dynamically to custom control?
Thanks.
The problem is not with the combination of the event being added late in the life cycle, and what you are trying to achieve with event handler.
As the error clearly states, the problem is with this line:
txtResult.Focus();
If you want to be able to set focus to controls, you must add your event handler on Init or Load.
You can work around this problem by setting the focus at client side using jquery.
var script = "$('#"+txtResult.ClientID+"').focus();";
You would have to emit this using RegisterClientScriptBlock.
The simplest change would be to move the focus() call:
bool focusResults = false;
protected void cfmTest_Sumit(object sender, EventArgs e)
{
txtResult.Text = "User Confirmed";
focusResults = true;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if(focusResults)
txtResult.Focus();
}
Are you sure txtResult.Text isn't being set again somewhere else?

How can i catch onclick event of Dynamically loaded control?

I have a dropdownlist (on Page) which has OnSelectedIndexChange event thats Loads different Control (ascx) dynamically each time ( with LoadControl Command) - into the page.
Each Control Has a Button(runat=server) and TextBox(runat=server).
When i click on the button - i cant get into the Onclick function .
How can i get into the OnClick Function of the Ascx ?
I know that each SelectedIndexChange its makes postback - so i know i have to save something in the viewstate. but i dont know how to save it and later get the values eneterd on the TexstBox. ( of Each ascx)
You need to add an event handler to the user control, like this:
public event EventHandler ButtonClick;
And in the click event of the button:
protected void Button1_Click(object sender, EventArgs e)
{
if (this.ButtonClick != null)
this.ButtonClick(this, e);
}
Then, from the page, you can get the click event like this:
<UC:MyUserControl ID="UserControl1" runat="server" OnButtonClick="UserControl1_ButtonClick" ... />
protected void UserControl1_ButtonClick(object sender, EventArgs e)
{
//Handle the click event here
}
If you're loading the controls dynamically, then you'll need to make sure the controls are rehydrated after postback, and emulate the code above by assinging the event handler through code:
MyUserControl ctrl = (MyUserControl)this.LoadControl("...");
ctrl.ButtonClick += new EventHandler(UserControl1_ButtonClick);

Raising the Load event within a dynamic loaded web usercontrol

I need to load a web user control dynamically.
Looking at http://weblogs.asp.net/srkirkland/archive/2007/11/05/dynamically-render-a-web-user-control.aspx, it states that the page lifecycle events are not fired.
I thought I might be able to raise the events through reflection. I cannot figure how to fire the events, am I missing something?
Thanks
Podge
You can do something like this before calling RenderControl:
Page page = new Page();
page.Controls.Add(report);
In this case Init method will be called.
an answer given on that link of yours
The standard Load event should fire just fine. The standard ASP.Net control events are raised for usercontrols. If you are wanting to fire events inside your usercontrol from the parent page then you'll want to do something like this:
Inside your usercontrol create an event and wire it up. In this example I'll call it from Page_Load:
public event EventHandler TestEvent;
protected void Page_Load(object sender, EventArgs e)
{
if (this.TestEvent != null)
{
this.TestEvent(this, e);
}
}
Inside your parent page wire up the user controls TestEvent:
protected override void OnInit(EventArgs e)
{
MyUserControl uc = LoadControl("~/PathToUserControl.ascx");
uc.TestEvent += new EventHandler(MyUserControl_TestEvent);
}
protected void MyUserControl_TestEvent(object sender, EventArgs e)
{
//this code will execute when the usercontrol's Page_Load event is fired.
}
Hope that helps!!

Categories

Resources