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).
Related
Building my first server control. Getting the "Value cannot be null. Parameter name: child" error in debug at the point indicated in my code. The textbox is created, then becomes nothing when the parent's page_load event is called. The page_load event fires between the OnInit and CreateChildControls in my control. Examples are hard to come by.
Public Class ContactForm
Inherits WebControl
#Region "Local variables"
Private _ShowFirstName As Boolean
Private tbFirstName As TextBox
#End Region
<Browsable(True), _
Bindable(True), _
Category("Appearance"), _
DefaultValue(True), _
Localizable(True), _
Description("Show First Name field")> _
Public Property ShowFirstName() As Boolean
Get
Return _ShowFirstName
End Get
Set(value As Boolean)
_ShowFirstName = value
End Set
End Property
Protected Overrides Sub OnInit(e As EventArgs)
If ShowFirstName = True Then
Dim tbFirstName As New TextBox
tbFirstName.ID = "tbFirstName"
tbFirstName.MaxLength = 30
tbFirstName.Text = "IM HERE"
End If
MyBase.OnInit(e)
End Sub
<<<<< --- NOTE: The Page_Load event of the parent fires here ->>>>>
Protected Overrides Sub CreateChildControls()
Me.Controls.Add(tbFirstName) <<---Error: Value cannot be null. Parameter name: child
If HasChildViewState Then
ClearChildViewState()
End If
MyBase.CreateChildControls()
End Sub
End Class
i haven't done this before but at the top you say, DefaultValue(True); does that mean it must have a default value? maybe if you set a default value OnInit (or make the prop false).
Okay, here is how I got it working.
I basically move the OnInit code into the CreateChildControls...duh!
I created a function (buildForm) that declares and adds all controls in one step like below.
Protected Overrides Sub CreateChildControls()
buildForm()
If HasChildViewState Then
ClearChildViewState()
End If
MyBase.CreateChildControls()
End Sub
SIDEBAR: Web User Control vs Custom Server Control
I spent the last 4-5 days comparing and experimenting with both controls. I've done a lot of User Controls over the years and just copied them into applications. Hated the maintenance that created.
I spent a full day trying to compile my current web controls into single dll that could be used kind of like server controls. I found it tedious and limited.
Many articles, including MSDN, had me scared of server controls saying it is much harder than a web control to create. I can say...so far...I am digging the Server Control. I wish I had done this in the beginning. True reuse. Don't fear the server control.
I have a custom control that inherits from .NET's CompositeControl class. This control overrides the CreateChildControls in order to build its child controls dynamically. I need the page to post back after a couple different javascript events occur on the client side.
In order to accomplish this, I create two hidden controls on the page so I can set their values with javascript, submit the page, and read the values out on server side. Here's is the code I use to create these two hiddens:
Protected Overrides Sub CreateChildControls()
hdEventName = New HiddenField()
Controls.Add(hdEventName)
hdEventName.ID = "hdEventName"
hdEventArgs = New HiddenField()
Controls.Add(hdEventArgs)
hdEventArgs.ID = "hdEventValue"
' other controls
' ...
End Sub
When a javascript event occurs I set the value attribute of the two hiddens and submit the page, like so:
hdEventName.value = 'EventName';
hdEventArgs.value = 'arg1,arg2';
document.forms[0].submit();
In the OnLoad method of my control, I attempt to check the Value property of the hdEventName and hdEventArgs controls, but it is always empty. However, Page.Request.Form(hdEventName.UniqueID) and Page.Request.Form(hdEventArgs.UniqueID) return correct values. The actual HTML in the markup also shows correct values after the page posts back.
Why is the Value property of the HtmlInputHiddens disconnected from the actual value that appears on the client?
Update
It appears that a control's properties get loaded from the form sometime after OnLoad occurs. Thus I was able to solve my problem by either moving the code that checks the two hidden fields into the OnPreRender method, or adding the following method to my code -
Private Sub Event_Handler(ByVal sender As Object, ByVal e As EventArgs)
Handles hdEventName.ValueChanged
' do stuff with hiddens
' ...
' reset the values back
hdEventName.Value = String.Empty
hdEventArgs.Value = String.Empty
End Sub
when the page posts back there's nothing to link the variable hdEventName to the control you previously created. what you're doing is akin to having an integer declared at the class level and setting it to 5 when you're creating child controls. there's nothing to maintain that value in that variable across postbacks.
if you want to get a reference to the control you created previously, you'd have to use
hdEventName = CType(Page.FindControl("hdEventName") , HiddenField)
(i'm guessing at this) or Request if you're only concerned with the value.
It appears that a control's properties get loaded from the form sometime after OnLoad occurs. Thus I was able to solve my problem by either moving the code that checks the two hidden fields into the OnPreRender method, or adding the following method to my code -
Private Sub Event_Handler(ByVal sender As Object, ByVal e As EventArgs)
Handles hdEventName.ValueChanged
' do stuff with hiddens
' ...
' reset the values back
hdEventName.Value = String.Empty
hdEventArgs.Value = String.Empty
End Sub
I have a base master page that specifies the main layout template of a website. It also handles some logic that changes tabs depending on the section, and also sets page meta information.
I'm dynamically loading nested master pages by looking at the querystring, loading up a record from the database, and setting the nested master page dynamically based on a value found in that record. I need to load dynamic nested master pages for layout and functional differences.
There is additional information in that record that I want to use in the base master page and in the dynamically loaded master page so I can avoid additional database calls.
Currently, I have set up a class that inherits MasterPage to act as the base class for the base master page. I have a shared (static) property that holds the object representing the database call that I want to share between the base master page and the nested, dynamically called master page.
It works, but it seems a little ugly. Are there any other better solutions?
You could always pass the record in the HttpContext.Items collection. Once it is in the Items collection it is available to every thing that can reach the HttpContext for the duration of the request.
Ok, I had to sleep on this one a bit, but I came up with a cleaner solution. I ended up using a base class for the page, instead of a base class for the master page. The base page sets the meta that I was going to set in the base master page.
Public Class PageBase
Inherits Page
Private _DocDetails As FolderDocument
Public Overridable ReadOnly Property DocDetails() As FolderDocument
Get
Return _DocDetails
End Get
End Property
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack() Then
SetMeta()
End If
End Sub
Protected Sub SetMeta()
If DocDetails IsNot Nothing Then
Page.Title = DocDetails.MetaTitle
If DocDetails.MetaKeywords <> String.Empty Then
Dim metaKeywords As New HtmlMeta()
metaKeywords.Name = "Keywords"
metaKeywords.Content = DocDetails.MetaKeywords
Page.Header.Controls.Add(metaKeywords)
End If
If DocDetails.MetaDescription <> String.Empty Then
Dim metaDescription As New HtmlMeta()
metaDescription.Name = "Description"
metaDescription.Content = DocDetails.MetaDescription
Page.Header.Controls.Add(metaDescription)
End If
End If
End Sub
End Class
..And then the aspx page inherits this base page and dynamically sets the master page.
<%# Page Language="VB" Inherits="PageBase" %>
<script runat="server">
Private _DocDetails As FolderDocument
Public Overrides ReadOnly Property DocDetails() As FolderDocument
Get
Return _DocDetails
End Get
End Property
Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs)
_DocDetails = FolderDocuments.GetFolderDocument()
If _DocDetails IsNot Nothing Then
If _DocDetails.MasterPage <> "" Then
Me.MasterPageFile = String.Format("~/templates/{0}.master", _DocDetails.MasterPage)
End If
End If
End Sub
</script>
...and in the dynamically called master page I can reference the page's base class by casting:
Dim parentPage As PageBase = DirectCast(Page, PageBase)
Response.write(parentPage.DocDetails.Title)
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
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" />