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
}
Related
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;
}
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?
I need to define 3 events in a Custom Control as OnChange, OnSave, and OnDelete.
I have a GridView and work with its rows.
Can you help me and show me this code?
Good article which can help you to achieve your task:
Custom Controls in Visual C# .NET
Step 1: Create the event handler in your control as below.
public event SubmitClickedHandler SubmitClicked;
// Add a protected method called OnSubmitClicked().
// You may use this in child classes instead of adding
// event handlers.
protected virtual void OnSubmitClicked()
{
// If an event has no subscribers registered, it will
// evaluate to null. The test checks that the value is not
// null, ensuring that there are subscribers before
// calling the event itself.
if (SubmitClicked != null)
{
SubmitClicked(); // Notify Subscribers
}
}
// Handler for Submit Button. Do some validation before
// calling the event.
private void btnSubmit_Click(object sender, System.EventArgs e)
{
OnSubmitClicked();
}
Step 2 : Utilize the event in the page where you register your control. The following code is going to be part of your page where your control is registered. If you register it, it will be triggered by the submit button of the control.
// Handle the SubmitClicked Event
private void SubmitClicked()
{
MessageBox.Show(String.Format("Hello, {0}!",
submitButtonControl.UserName));
}
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);
I have an aspx page with two custom buttons that looks like this:
<cfw:Button runat="server" OnServerClick="CreateProduct" name="Create product" />
<cfw:Button runat="server" OnServerClick="OrderProduct" name="Order product" />
I want 1 button that creates and orders the product at the same time. So I basically want to ask can I add multiple event handlers in the .aspx to the same event?
The button event itself supports this and it is programatically possible:
public event ProcessEventHandler ServerClick
{
add
{
Events.AddHandler(serverClick, value);
PostBack = true;
}
remove { Events.RemoveHandler(serverClick, value); }
}
Rules of the game (because of internal / company standards):
I can't use stuff like <% %>
I'm not allowed to add Code Behind / Code beside to the page
I might need to be able to add 4 event handlers, so don't come with solutions like SecondOnServerClick (I will vote you down ;-) )
I'm looking forward to your input!
Well here is my solution: Based on your constraints, it seems the only possibility is to either (a) inherit your custom framework button and create a subclass, or (b) modify the existing framework button.
Here is an implementation which works well ( I tested it :) ) by subclassing the System.Web.UI.WebControls.Button class, and test page:
using System.Web.UI.WebControls;
namespace StackOverflowWeb
{
public class MultiCastButton : Button
{
public ListItemCollection ClickEventList { get; set; }
private void SetEventHandlers()
{
// convert listitem values to EventHandler type
Func<ListItem, EventHandler> getEventHandler = ev =>
EventHandler.CreateDelegate(
typeof(EventHandler), this.Page, ev.Value) as EventHandler;
if (ClickEventList != null && ClickEventList.Count > 0)
{
for (var i = 0; i < ClickEventList.Count; i++)
{
this.Click += getEventHandler(ClickEventList[i]);
}
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// must occur OnInit because 'this.Page'
// is null prior to this event firing
SetEventHandlers();
}
}
}
Then, you have the test page (codebehind) - I know you said you don't have codebehind, so these event handlers can live in any class or class library, and you can register that class on the front of the page. This solution works in an isolated test environment (i.e., new ASP.net web project).
You might have to modify the code in the getEventHandler() method, instead of the target type being this.Page, you may use whatever type contains your actual event handler voids.
public partial class _Default : System.Web.UI.Page
{
public void Test_Click(object sender, EventArgs args)
{
ResultPanel.Controls.Add(new Label() { Text = "Test Click Executed" });
}
public void Test_Click2(object sender, EventArgs args)
{
ResultPanel.Controls.Add(new Label() { Text = "Test Click 2 Executed" });
}
public void Test_Click3(object sender, EventArgs args)
{
ResultPanel.Controls.Add(new Label() { Text = "Test Click 3 Executed" });
}
public void Test_Click4(object sender, EventArgs args)
{
ResultPanel.Controls.Add(new Label() { Text = "Test Click 4 Executed" });
}
}
And finally your declaration on the front
<%# Register Namespace="StackOverflowWeb" TagPrefix="sow" Assembly="StackOverflowWeb" %>
<style> span { display: block; }</style>
<sow:MultiCastButton runat="server" ID="TestClickMultiCastButton" >
<ClickEventList>
<asp:ListItem>Test_Click</asp:ListItem>
<asp:ListItem>Test_Click2</asp:ListItem>
<asp:ListItem>Test_Click3</asp:ListItem>
<asp:ListItem>Test_Click4</asp:ListItem>
</ClickEventList>
</sow:MultiCastButton>
<asp:Panel runat="server" ID="ResultPanel" />
Note that I am using ListItem and a ListItemCollection because it lends itself most easily to being declared in the UI of an ASP.net web forms application.
I hope you find this useful! It is my first answer here on StackOverflow, although I have been an avid reader for a long time.
I believe you've no way to add more than a handler in design time.
If you can't use server code in the page - which is a very bad design principle -, I'd point that you have no options.
By the way, if I understood you well, you've a custom button control with your own event accessors defined, as you shown in the question.
I only see one solution.
You can add a new property called OnServerClick which is of type of string and change current ServerClick event accessor to another identifier.
Now OnServerClick is a comma-separated list of server event handlers, and during the Init, you can bind these handlers to the event.
You can achieve that and you can have what you want.
I hope you're not going to vote down no one ;) We're here to support others.