How do you handle the Web User Control event? I notice my custom web user control have a event call OnError but it never fire when i tweak the control to fail. The control is basically a custom gridview control. I search for web user control event handling over the net but i haven't find a article that address what i looking for. Can someone do a quick explanation or point me to the right direction?
thank
You didn't mention what flavour of ASP.NET, so I'll make the assumption of VB - C# is largely the same with the exception of how the event handler is attached.
The normal pattern you would expect to see is something along these lines:
User Control "MyUserControl" CodeBehind
Public Event MyEvent(ByVal Sender As Object, ByVal e As EventArgs)
Private Sub SomeMethodThatRaisesMyEvent()
RaiseEvent MyEvent(Me, New EventArgs)
End Sub
Page Designer Code
Private WithEvents MyUserControl1 As System.Web.UI.UserControls.MyUserControl
Page or other Control that wraps MyUserControl instance CodeBehind
Private Sub MyUserControlEventHandler(ByVal Sender As Object, ByVal e As EventArgs) _
Handles MyUserControl.MyEvent
Response.Write("My event handled")
End Sub
In some instances, you see something called Event Bubbling which doesn't follow this kind of pattern exactly. But in the basic sense of handling events from a user control to a wrapper control or the page it sits in, that's how you would expect it to work.
I had an issue with a custom control that was throwing exceptions which were not firing Error event. Thus I could not catch exceptions from this control and display appropriate message in the ASP.NET page.
Here is what I did. I wrapped the code in the custom control in a try..catch block and fired the Error event myself, like this:
// within the custom control
try
{
// do something that raises an exception
}
catch (Exception ex)
{
OnError(EventArgs.Empty); // let parent ASP.NET page handle it in the
// Error event
}
The ASP.NET page was handling the exception using the Error event like this:
<script runat="server">
void MyCustomControl_Error(object source, EventArgs e)
{
MyCustomControl c = source as MyCustomControl;
if (c != null)
{
// Notice that you cannot retrieve the Exception
// using Server.GetLastError() as it will return null
Server.ClearError();
c.Visible = false;
// All I wanted to do in this case was to hide the control
}
}
</script>
<sd:MyCustomControl OnError="MyCustomControl_Error" runat="server" />
Related
I am sure everyone who programmed with user controls for asp.net came across situations where you needed a certain way to check whether a user control has been loaded for the first time or it has been re-loaded. Has anyone come up with any other solutions other than setting hidden "currentOpenControl" flag(s). If you are wondering as to do I need to check whether control is open for first time or re-open again, then one of the big reasons is databinding. When the control is open for first time, that is when I want to databind, afterwards on re-open, if I databind again I will lose any changes user might have added.
So I am just wondering if anyone has a more elegant solution than setting flags whether control is open or not.
Thanks
The only way I've ever managed to do this is by using the ViewState...
Private Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
If ViewState["postBack"] Is Nothing Then
' Do everything you'd normally do with Page.IsPostBack
ViewState["postBack"] = true
End
End Sub
Or for C#...
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["postBack"] == null)
{
// Do everything you'd normally do with Page.IsPostBack
ViewState["postBack"] = true;
}
}
You can get using this, its in VB.NET convert to c#
Private currentPage As Page = HttpContext.Current.Handler
If (Not currentPage.IsPostBack) Then
End if
I have a master page and a user control
I have written an event in usercontrol and i want to call that event in my master page.
following are my codes
masterpage ----------- ( I THINK THIS PART IS CORRECT, IT'S DOING WHAT IT IS SUPPOSE TO DO;CALLING THE USER CONTROL FUNCTION. )
Dim App_Cl_tpPerson As New App_Cl_tpPerson
App_Cl_tpPerson.PersonAdd_Click(sender, e)
usercontrol page ---------- ( I FEEL THE PROBLEM IS HERE )
Public Sub PersonAdd_Click(ByVal sender As Object, ByVal e As EventArgs)
Try
If Req_No = 0 Then
Req_No = Convert.ToInt32(Request.QueryString("reqID"))
End If
Catch ex As Exception
End Try
End Sub
The error message is "OBJECT REFERENCE NOT SET TO AN INSTANCE OF AN OBJECT"
.
If you have created a control in your master page, you need to place an event handler there as well. The reason you are getting the error is because the master page's control is looking for the event handler in the master page's class and there is none defined.
Since all you are doing is getting the QueryString value, which the master page has access to, you can accomplish what you want by simply moving the method from your derived page to your master page.
Then, since you need the Req_No value to be accessible to your templated page, you must add a public property or method to your master page to allow your templated page to access the value.
Finally, to use your property/method call in your templated page, you would do the following:
Public Sub DoSomething()
Dim Req_No As Integer = CType(Me.Master, MyMasterClassName).Req_NoProperty
End Sub
(Note, I don't use VB all that often, so I'm not sure if the CType call would work, but the general idea is you need to cast the Page class' reference to the Master Page to your specific Master Page's class since that is where the property or method you wrote resides).
I'm having a problem with a Web Control that is dynamically created and inserted in my page. I create a couple of LinkButtons, depending on the data of the search that was made, and I'm trying to add an Event Handler to each of the Buttons, so it would filter the result.
The controls are initialized properly, but the event is never fired.
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
Controls.Clear()
Dim btn As Controls.LocalizableLinkButton
For Each element As Generic.KeyValuePair(Of String, ResultFilterData) In m_list
btn = New LocalizableLinkButton
btn.ID = m_Name & "$lnk" & count
btn.Label = element.Value.Label.Append(" (" + CStr(element.Value.Count) + ")")
btn.CommandArgument = element.Value.Key
AddHandler btn.Click, AddressOf Me.btn_Click
Controls.Add(btn)
Next
End Sub
Since this code is in Page_Init all the controls should be recreated on a postback. (The LocalizableLinkButton is just an extension of a LinkButton to add multilingual features to the text).
The problem is that the method btn_Click is never called. The Link Buttons are properly initialized on the callback, with the same ID's as before. But the event doesn't fire.
I'm using ASP.Net 2.0
Any ideas?
I finally figured out the problem ASP.NET had with my Link Buttons.
The error was in using a '$' sign in my ID for each LinkButton. ASP.NET apparently uses the $ sign to build the control hierarchy when it creates the Postback Javascript. Therefore it thinks that the LinkButtons are nested within a control that does not exist. And so the events aren't fired of course.
Once I removed the $ signs it worked properly.
You probably want to put this piece of code in the Page_Load and see. It's generally advised not to access controls in this Page_Init as there is no guarantee of the controls been created at this stage.
I'm no VB guy but i put this into the codebehind of the default.aspx and it works fine.
protected void Page_Load(object sender, EventArgs e)
{
Button button = new Button();
button.Click += new EventHandler(button_Click);
button.Text = "test";
Form.Controls.Add(button);
}
void button_Click(object sender, EventArgs e)
{
throw new NotImplementedException();
}
I have the following BasePage class...
Public Class BasePage
Inherits System.Web.UI.Page
Private litError As Literal
Protected SO As Session
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
SO = Session.Item("SO")
If SO Is Nothing Then
Session.Abandon()
Response.Redirect("~/timeout.htm")
End If
litError = Page.FindControl("litError")
If litError IsNot Nothing Then
litError.Visible = False
End If
End Sub
Protected Sub ShowMessage(ByVal Message As String)
Show(Message, "message")
End Sub
Protected Sub ShowError(ByVal Message As String)
Show(Message, "error message")
End Sub
Protected Sub ShowSuccess(ByVal Message As String)
Show(Message, "success message")
End Sub
Private Sub Show(ByVal Message As String, ByVal CssClass As String)
If litError IsNot Nothing Then
litError.Text = String.Format("<span class=""{0}"">{1}</span>", CssClass, HttpUtility.HtmlEncode(Message))
litError.Visible = True
End If
End Sub
End Class
Every page in this application inherits this class. The SO variable represents a custom session class, that is very simple and just holds a couple of basic settings to be used throughout the application. The problem is, my Page_Load in this base class does not fire if a natural postback occurs (in this case, it is a gridview postback by sorting/paging). Then later in my code when I reference SO, I get a null reference exception because it hasn't been pulled from session.
Why doesn't the base Page_Load fire?
Try moving your code into the Page_Init event.
Microsoft has some info on each event in the lifecycle http://msdn.microsoft.com/en-us/library/ms178472.aspx. This MSDN page tells you what types of things you should handle in each event.
You might want to think about implementing SO as a property, where the Get does (not sure if this is correct VB...)
Dim so As Session = Session.Item("SO")
If so Is Nothing Then
Session.Abandon()
Response.Redirect("~/timeout.htm")
End If
return so
It could be that something else is happening in the Init events that is causing it to fail. So rather than it not being called it just hasn't been called yet.
It could be that the autoevent wireup isn't wiring it up correctly, tend to override the OnInit event and attach the events manually myself, I have also read somewhere that this improves perfomance by not requiring the framework to do heaps of reflection on every post.
But back to your problem... try making the SO object private and create a property accessor for it that first checks that if the private is set, if not set it, before returning the private variable. If it isn't set and can't be found then it can abort the same way you are doing in the Load. This means that to load the variable you won't be dependent on the Page_Load from firing and thus the SO object should be available for you during the init routines, if you need it.
I'm working on an ASP.NET page, using VB.NET and I have this hierarchy:
Page A
- Web User Control 1
- Web User Control A
- Web User Control B
- Web User Control C
I need to raise an event from Web User Control B that Page A will receive (the event flow will be Web User Control B -> Web User Control 1 -> Page A).
My only approach so far has been this:
1) Add a custom event declaration to both Web User Control B and Web User Control 1 and simply RaiseEvent twice until it gets to Page A (this seems ugly and I don't particularly like it).
My other idea was to create a custom Event class that inhertis from some magical base Event class and create an instance of it in both Web User Control B and Web User Control 1, but that is proving fruitless because I can't find any event base classes (maybe b/c they're aren't any, since it appears to be a keyword, not a class name).
Any help would be appreciated! Thanks and happy coding!
You can use the BubbleEvent concept to do this. A BubbleEvent goes up the control hierarchy until someone handles it. The GridView and Repeater controls do this with their Row/ItemCommand events.
You could implement it into WebUserControl1, turning it into a standard event for the page (like the GridView does):
Class UserControl1 ' Parent
Protected Override Function OnBubbleEvent(sender as Object, e as EventArgs) as Boolean
Dim c as CommandEventArgs = TryCast(e, CommandEventArgs)
If c IsNot Nothing Then
RaiseEvent ItemEvent(sender, c)
Return True ' Cancel the bubbling, so it doesn't go up any further in the hierarchy
End If
Return False ' Couldn't handle, so let it bubble
End Function
Public Event ItemEvent as EventHandler(Of CommandEventArgs)
End Class
Class UserControlB ' Child
Protected Sub OnClicked(e as EventArgs)
' Raise a direct event for any handlers attached directly
RaiseEvent Clicked(Me, e)
' And raise a bubble event for parent control
RaiseBubbleEvent(Me, New CommandEventArgs("Clicked", Nothing))
End Sub
Protected Sub OnMoved(e as EventArgs)
' Raise a direct event for any handlers attached directly
RaiseEvent Moved(Me, e)
' And raise a bubble event for parent control
RaiseBubbleEvent(Me, New CommandEventArgs("Moved", Nothing))
End Sub
End Class
Class PageA
Sub UserControl1_ItemEvent(sender as Object, e as CommandEventArgs) Handles UserControl1.ItemEvent
Response.Write(sender.GetType().Name & " was " & e.CommandName)
End Sub
End Class
Or, do it directly in the page. UserControlB (Child) is the same as above, and UserControl1 (Parent) doesn't need to do anything special - OnBubbleEvent defaults to returning False, so the event bubbles up:
Class PageA
Protected Override Function OnBubbleEvent(sender as Object, e as EventArgs) as Boolean
If sender Is UserControlB Then
Dim c as CommandEventArgs = TryCast(e, CommandEventArgs)
If c IsNot Nothing Then
Response.Write(sender.GetType().Name & " was " & c.CommandName)
Else
Response.Write(sender.GetType().Name & " raised an event, with " & e.GetType().Name & " args)
End If
Return True ' Cancel the bubbling, so it doesn't go up any further in the hierarchy
End If
Return False ' Not handled
End Function
End Class
If your initial event is from a server control (like a Button.Click), then it will have been coded to already raise the bubble event - so UserControlB (Child) doesn't need to do anything to get that to the parent either. You just need to call RaiseBubbleEvent for any of your custom events, or if you want to transform the EventArgs in some way.
The real question here is is the actual action in Web UserControl B something that should notify both, OR, is WebUserControl1 responsible for some processing BEFORE notifying the page.
If each step of the chain has a specific action, your method of raising two events is proper. If it is in a manner where the event just needs to notify everyone you will want to look at different subscription methods to communicate.
Create a Assembly (or Namespace) that is referenced by everything.
Create a interface with the methods you need.
Create a class that manages objects that implemented the interface.
Have Page A implement the interface
Have Page A register itself with the manager class done in step #3
Now Web UserControl B can raise the event by retrieving the page from the manager and calling the method on the interface that raises the event you need.
You avoid tightly coupling the page to the webcontrol because you are using a interface.
Likely you will find that you will have a multiple interface for different areas of your project. For example in my CAM project I have a interface for the Setup Parameters UI, the Shape Entry UI, and the Cut Entry UI. On our website we have different product categories that uses different interfaces. (Software, Machinery, Services, etc).
You can create a public method in Page A which gets called from Web User Control B instead of raising an event up the entire control tree.
This would not be my first choice since this will cause tight coupling between those classes but I hope it solves your problem.
Sample Page:
Public Partial Class TestPage
Inherits Page
Public Sub PerformAction()
'Whatever needs to be done on Page A
End Sub
End Class
Sample User Control:
Public Partial Class TestControl
Inherits UserControl
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'This will call the Page, obviously this will only
'work when the control is on TestPage
CType(Page, TestPage).PerformAction()
End Sub
End Class