Stumped With Custom Property on User Control - asp.net

I have created an ASP.NET usercontrol. When I explicity provide the value for a custom property, the value is passed to the control. However, when I try to use the value from a datasource, the value is not passed to the control.
The user control sits within a FormView. The FormView successfully displays the underlying record. I am attempting to pass to the control a value in a column from the FormView's datasource. This works
<asp:formview .... />
<editTemplate>
<uctrl:DateSelector ID="DateSelector1" runat="server" DateValue="5/30/2011" /><br />
<%#Eval("MilestoneDate")%>
</editTemplate>
</asp:formview>
This does not...
<asp:formview .... />
<editTemplate>
<uctrl:DateSelector ID="DateSelector1" runat="server" DateValue='<%#Eval("MilestoneDate")%>' /><br />
<%#Eval("MilestoneDate")%>
</editTemplate>
</asp:formview>
I have confirmed that MileStoneDate does have a value in it. For whatever the reason, the value is not being passed to the control, however the control does recognize a literal value.
Imports Microsoft.VisualBasic
Imports System.Data
Imports System.Data.SqlClient
Imports System.Web.UI
Imports System.ComponentModel
Partial Class content_WebUserControl
Inherits System.Web.UI.UserControl
<Bindable(True, BindingDirection.OneWay)>
Public Property DateValue() As String
Get
Return _DateValue
End Get
Set(ByVal value As String)
_DateValue = value
End Set
End Property
Private _DateValue As String
Protected Sub Page_Load() Handles Me.Load
If IsDate(Me.DateValue) Then
Dim NewDate As DateTime = CDate(Me.DateValue)
LabelSelectedDateDisplay.Text = Me.DateValue
LabelSelectedDateDisplay_DayOfWeek.Text = NewDate.ToString("dddd")
TextBoxSelectedDate.Text = Me.DateValue
Else
LabelSelectedDateDisplay.Text = ""
LabelSelectedDateDisplay_DayOfWeek.Text = ""
TextBoxSelectedDate.Text = ""
End If
End Sub
End Class
I was refered to the post at this URL ASP.NET User Control : can't initialize a user control property using Eval("...")
However, based on my understanding of the post, what I have should be working.

You need to use ViewState to persists DateValue between page requests.
Public Property DateValue() As String
Get
IF IsNothing(ViewState("datevalue") Then
return String.Empty
End If
return ViewState("datevalue").ToString()
End Get
Set(ByVal value As String)
ViewState("datevalue")=value
End Set
End Property
Or store value directly to the controls:
Public Property DateValue() As String
Get
Return LabelSelectedDateDisplay.Text
End Get
Set(ByVal value As String)
If IsDate(value) Then
Dim NewDate As DateTime = CDate(value)
LabelSelectedDateDisplay.Text = NewDate
LabelSelectedDateDisplay_DayOfWeek.Text = NewDate.ToString("dddd")
TextBoxSelectedDate.Text = NewDate
Else
LabelSelectedDateDisplay.Text = ""
LabelSelectedDateDisplay_DayOfWeek.Text = ""
TextBoxSelectedDate.Text = ""
End If
End Set
End Property

The problem is that databinding doesn't occur on your formview until after Page.Load, and you are checking the value of the property during that time. If you want the value to be set in Page.Load you need to manually bind using FormView.Databind().
Alternatively, you can change the code you listed in your custom control from handling Page.Load to handle Page.Prerender, if nothing requires that code to execute earlier.

It looks like the issue might be timing/event related.
When you set a property with <%# %>, the value is assigned to the property during the Control's databinding event. If you look for it at Page_Load() time, it won't be there yet.
If you change your code to check the value in the PreRender event, it should be there.

Related

Specified Cast is not valid when DataBind to Nullable DateTimeOffset and field is NULL

I've created a simple CompositeControl and exposed a Nullable DateTimeOffset property.
I'm binding the control to a SQL Server DateTimeOffset field using
DateTimeOffset='<%# Bind("myDateTimeOffsetField") %>'
This works great when the DateTimeOffset field has a value.
But when the field is NULL I get a "Specified Cast is not valid" error.
How do I stop this error and set my property to Nothing when the field is NULL?
I thought this would be the default behaviour!
Property definition is:
Public Property DateTimeOffset As DateTimeOffset?
Later comment:
I've found that this works if I change from using Bind to:
DateTimeOffset='<%# iif(IsDbNull(Eval("myDateTimeOffsetField")), Nothing, Eval("myDateTimeOffsetField")) %>'
But then I don't get "myDateTimeOffsetField" passed as an argument in the FormView.ItemUpdating event (yes, this is in a FormView control) since ASP.NET assumes I'm not binding back to the Database.
Actual Code (Added by Request)
This is the Property in my Composite Control that I'm trying to bind to:
Public Property DateTimeOffset As DateTimeOffset?
Get
Return CType(ViewState("DTO"), DateTimeOffset?)
End Get
Set(value As DateTimeOffset?)
ViewState("DTO") = value
End Set
End Property
Heres the markup for the Binding. The Control is in the EditItemTemplate of a FormView which is bound to a SQL DataSource returning a field called [dtoMldRejOn] with an optional DateTimeOffset value.
<APS:DateTimeOffsetControl runat="server" id="dtocMldRejOn" TextBoxCssClass="inputdatetime" ValidationGroup="vw1" FieldName="<%$ Resources: Resource, rxgFrom %>" DateTimeOffset='<%# Bind("dtoMldRejOn") %>' WindowsTimeZoneID="<%# me.WindowsTimeZoneID %>" IsRequired="false" />
As you can see, my Composite control is for handling DateTimeOffset values. It all works great unless the DateTimeOffset field [dtoMldRejOn] from the database is NULL, then I get the exception.
I have never created bindable controls before, but I would like to make suggestion. How about setting your DateTimeOffset property to be of type Object. That way, the property will accept any data types including DBNull.
And once inside the Set code, check if the value passed is DBNull.Value. If so, create a new empty DataTimeOffset? object and save it in the ViewState.
If non DBNull values, throw error if it cannot be be converted to datetime.
I didn't try this though so I don't know if this will work or not.
################ UPDATED ANSWER ################
My suggestion is, you create 2 properties as follows:
Public Property DateTimeOffset() As DateTimeOffset?
Get
Return DirectCast(ViewState("DTO"), DateTimeOffset?)
End Get
Set(ByVal Value As DateTimeOffset?)
ViewState("DTO") = Value
End Set
End Property
<Bindable(True, BindingDirection.TwoWay)>
Public Property DbDateTimeOffset As Object
Get
Return Me.DateTimeOffset
End Get
Set(value As Object)
If IsDBNull(value) OrElse value Is Nothing Then
Me.DateTimeOffset = New DateTimeOffset?
Else
Me.DateTimeOffset = DirectCast(value, DateTimeOffset?)
End If
End Set
End Property
So in your markup, the binding will be to the DbDateTimeOffset property:
DbDateTimeOffset='<%# Bind("myDateTimeOffsetField") %>'
While in code behind, you can use the other property to read the property without having to cast.
Based on this post,
I think you just need to mark your property with the Bindable attribute:
<System.ComponentModel.Bindable(True)> _
Public Property DateTimeOffset As DateTimeOffset?
The problem is that DbNull is different from Nothing and you must explicitly write that somewhere in your code. My first idea here was to use the binding events to add the value. So if you keep you code like this:
DateTimeOffset='<%# iif(IsDbNull(Eval("myDateTimeOffsetField")), Nothing, Eval("myDateTimeOffsetField")) %>'
You can manually add the DateTimeOffset parameter in the Updating events before the binding proceeds (I can update the answer later with more details on this if you want)
Anyway, after reading your code more carefully I thought that maybe the CType isn't casting correctly. Have you tried replacing your Get with something like this?
Get
Return If(IsDbNull(ViewState("DTO")), Nothing, CType(ViewState("DTO"), DateTimeOffset?))
End Get
Your code with iif ... works for me. I have created a testing control and a page version with code behind pages ( I have tested code behind version too but this one is easier to publish). I have VS2010 target framework is 4.0.
First the control(TstNullableCtrl.ascx):
<%# Control Language="vb" AutoEventWireup="false" %>
<script runat="server">
Public Property DateTimeOffset As DateTimeOffset?
</script>
<div ID="Label1" runat="server" >
<%= If(DateTimeOffset.HasValue, DateTimeOffset.ToString, "Empty")%>
</div>
and the page - a table with two rows and two columns bound to datagrid (TstNullablePage.aspx):
<%# Page Language="vb" AutoEventWireup="false" %>
<%# Import Namespace="System.Data"%>
<%# Register src="TstNullableCtrl.ascx" tagname="TstNullableCtrl" tagprefix="uc1" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim tbl As New DataTable
tbl.Columns.Add(New DataColumn("id", GetType(Integer)) With {.AutoIncrement = True})
tbl.Columns.Add(New DataColumn("myDateTimeOffsetField", GetType(DateTimeOffset)))
Dim row As DataRow
row = tbl.NewRow : row("myDateTimeOffsetField") = DateTimeOffset.Now
tbl.Rows.Add(row)
row = tbl.NewRow : row("myDateTimeOffsetField") = DBNull.Value
tbl.Rows.Add(row)
tstgrd.DataSource = tbl : tstgrd.DataBind()
End Sub
</script>
<html>
<body>
<form id="form1" runat="server">
<asp:datagrid ID="tstgrd" runat="server">
<Columns>
<asp:TemplateColumn HeaderText="Offset">
<itemtemplate>
<uc1:TstNullableCtrl ID="WithNullableDate1" runat="server"
DateTimeOffset='<%# iif(IsDbNull(Eval("myDateTimeOffsetField")), Nothing, Eval("myDateTimeOffsetField")) %>' />
</itemtemplate>
</asp:TemplateColumn>
</Columns>
</asp:datagrid>
</form>
</body>
</html>
And expected result (a value when there is and 'Empty' when is null)
Edit
However I think that to "avoid complication" best solution is as follows:
Public _DateTimeOffset As Object
Public Property DateTimeOffset As Object
Get
If IsDBnull(_DateTimeOffset) then Return Nothing
Return Ctype(_DateTimeOffset, DateTimeOffset?)
End Get
Set(value As Object)
_DateTimeOffset = value
End Set
End Property
I know this question have been already answered I just would like to document my solution which is in between those two answers as I have came across this today:
Private _AssetId As Object
<Bindable(True, BindingDirection.TwoWay)>
Public Property AssetId() As Object
Get
If _AssetId Is Nothing Then
Return Nothing
Else
Return CType(_AssetId, Integer)
End If
End Get
Set(ByVal value As Object)
If value Is Nothing OrElse IsDBNull(value) OrElse CType(value, String) = "" Then
_AssetId = Nothing
Else
_AssetId = CType(value, Integer)
End If
End Set
End Property

System.ArgumentException: String value can not be converted to a date

I have a web form that uses an Ajax date calendar. This works fine. The problem that i have is that when i submit my form i get the following message.
'String value can not be converted to a date' .AgendaDate = New SmartDate(txtAgendaDate.Text)
Here is my web form that holds the calendar and the associated text box...
<td>
<asp:TextBox ID="txtAgendaDate" runat="server" ForeColor="Black" ></asp:TextBox>
</td>
<td>
<asp:ImageButton runat="Server" ID="ImageButton1" ImageUrl="~/images/calendarpic.png"
AlternateText="Click here to display calendar" />
<cc1:calendarextender ID="CalendarExtender1" runat="server"
TargetControlID="txtAgendaDate" PopupButtonID="ImageButton1" >
</cc1:calendarextender>
</td>
I have a class with the associated properties on it for the web form. The rest of the fields work and submit data to the database except the textfield for the ajax calendar.
Here is my stripped down version for the code for the class and the txtAgendaDate code...
#Region " Agenda Variables "
'Declare Variables and data types and set default values
Private mAgendaID As Integer = 0
Private mOrganiser As String = ""
Private mMeeting As String = ""
Private mAgendaDate As SmartDate = New SmartDate()
#End Region
#Region " Constructors "
Public Sub New()
End Sub
Public Sub New(ByVal reader As SafeDataReader)
' Public Sub New(ByVal reader As SQLDataReader)
'Combine variables & property types
With reader
mAgendaID = .GetInt32("AgendaID")
mOrganiser = .GetString("Organiser")
mMeeting = .GetString("Meeting")
mAgendaDate = .GetSmartDate("AgendaDate")
End With
End Sub
#End Region
#Region "Properties"
'Define form field properies so that they can be used when adding the data to the database on the add button is pressed.
Public Property AgendaID() As Integer
Get
Return mAgendaID
End Get
Set(ByVal Value As Integer)
mAgendaID = Value
End Set
End Property
Public Property Organiser() As String
Get
Return mOrganiser
End Get
Set(ByVal value As String)
mOrganiser = value
End Set
End Property
Public Property Meeting() As String
Get
Return mMeeting
End Get
Set(ByVal value As String)
mMeeting = value
End Set
End Property
Public Property AgendaDate() As SmartDate
Get
Return mAgendaDate
End Get
Set(ByVal Value As SmartDate)
mAgendaDate = Value
End Set
End Property
#End Region
End Class
Here is my command that looks connects to the DB and at the stored procedure and also has the parameters.
Public Class Agenda_TempDAL
Public Shared Function AddAgenda_Temp(ByVal Agenda_Temp As Agenda_Temp) As Integer
'Declare i as integer as 0
Dim iAgendaID As Integer = 0
'Database conn, this is linked to the web config file .AppSettings
Using dbconnection As New SqlConnection(ConfigurationManager.AppSettings("dbconnection"))
dbconnection.Open()
'Command to state the stored procedure and the name of the stored procedure
Using dbcommand As SqlCommand = dbconnection.CreateCommand
With dbcommand
.CommandType = CommandType.StoredProcedure
.CommandText = "Stored_Proc_Name"
'Create parameter for AgendaID and output
Dim oParam As New SqlParameter
oParam.ParameterName = "#AgendaID"
oParam.Direction = ParameterDirection.Output
oParam.SqlDbType = SqlDbType.Int
'Create parameters for the remaining fields
.Parameters.Add(oParam)
.Parameters.AddWithValue("#Organiser", Agenda_Temp.Organiser)
.Parameters.AddWithValue("#Meeting", Agenda_Temp.Meeting)
.Parameters.AddWithValue("#AgendaDate", Agenda_Temp.AgendaDate.DBValue)
'Simply execute the query
dbcommand.ExecuteNonQuery()
End With
End Using
End Using
'Need to return the agendaID as an integer.
Return iAgendaID
End Function
End Class
And here is the code behind the button ion the web page. This is the page that causes the error based on the property / field. The problem lies on this line...
.AgendaDate = New SmartDate(txtAgendaDate.Text)
The whole code for the button is here...
Protected Sub btnAddAgendaTemplate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddAgendaTemplate.Click
'This works alongside the Class named Agenda_Temp which has the properties and DB connection assigned to it for each web form field.
Dim oAgenda_Temp As New Agenda_Temp
'Within the object Agenda_Temp Class use the properties defined.
'They are required to be defined in the Agenda_Temp/ app code so we can use them within here.
With oAgenda_Temp
.Organiser = txtOrganiser.Text
.Meeting = txtMeeting.Text
.AgendaDate = New SmartDate(txtAgendaDate.Text)
'Within the object Agenda_Temp class use the defined DAL which includes all the DC connect and stored procedures.
oAgenda_Temp.AgendaID = Agenda_TempDAL.AddAgenda_Temp(oAgenda_Temp)
End With
End Sub
End Class
I understand that its telling me that the string value cannot be converted to a date but i don't know hoe to resolve this as i am new to .net 2010?
Any help much appreciated.
Convert the string to a date before newing it:
From MSDN:
string date = "01/08/2008";
DateTime dt = Convert.ToDateTime(date);
Your's would become
DateTime dt = Convert.ToDateTime(txtAgendaDate.Text)
Then pass the date to your SmartDate constructor:
oAgenda_Temp.AgendaDate = new SmartDate(dt)
The final result:
With oAgenda_Temp
.Organiser = txtOrganiser.Text
.Meeting = txtMeeting.Text
.AgendaDate = New SmartDate(Convert.ToDateTime(txtAgendaDate.Text))
'Within the object Agenda_Temp class use the defined DAL which includes all the DC connect and stored procedures.
oAgenda_Temp.AgendaID = Agenda_TempDAL.AddAgenda_Temp(oAgenda_Temp)
End With
As others have pointed out, you need to convert the input value to a DateTime. I don't know what the SmartDate() function is doing, but the error message clearly indicates that the value cannot be converted to a date.
Secondly, I would add some validation to make sure that the input is valid before you submit the page. Use the RequiredFieldValidator and CompareValidator or RegularExpressionValidator:
<asp:TextBox ID="txtDate" runat="server" ... />
<asp:RequiredFieldValidator ID="reqDate" runat="server" ErrorMessage="Required" Display="Dynamic" ControlToValidate="txtDate"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="regDate" runat="server" ControlToValidate="txtDate" ErrorMessage="Please enter a valid date in the format (mm/dd/yyyy)" ValidationExpression="^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$"></asp:RegularExpressionValidator>

Connect reusable ASP.NET WebControl to a method for loading data

I'm trying to create a control that can extend other webcontrols and set some properties like visible and enabled, based on user permissions.
Here's an example where your user role would need to include the "CanSave" permission:
<asp:Button ID="btn1" runat="server" Text="Save"/>
<myControls:PermissionsExtender runat="server" ControlToSet="btn1" Permission="CanSave"/>
I'm trying to keep this reusable, that's why the PermissionExtender is in a separate project that can not have any dependencies to other projects. To make a decision, the control of course needs to get this info from somewhere else (database or something). I made another control and, using events, the above extender will be set by a master control, so only that needs to know where to look up the information.
The master control now needs to be configured to know where the information about roles and permissions will be coming from. My idea was to have an interface inside the reusable project, and implement that somewhere else, then configure my control to go and find the class that implements the method I need and load it through reflection. But I'm unclear how this could work. I would probably place the master control in the masterpage and supply it a class name like PermissionClass="SecurityLibrary.PermissionsClass". Kinda like ObjectDatasource does it, but other suggestions are welcome.
The method signature would be like:
bool HasPermission(string permission)
It would know the current users role and using that combination, looks up if the role includes the permission.
How can I wire up a call from the control to a method inside my main project that can supply the necessary information without making them dependent.
I think I've got something that will work for you (tested fine for me but I may have misunderstood part of what you were looking for). With this implementation the asp.net designer code will look like this:
<web:PermissionMasterControl runat="server" ID="masterController" PermissionClass="SecurityLibrary.RandomPermissionClass" />
<asp:Button ID="btnSave" runat="server" Text="save" />
<web:PermissionExtender runat="server" ControlToSet="btnSave" Permission="CanSave" MasterControllerID="masterController" />
Now for the SecurityLibrary. Pretty straight forward, I included a simple "RandomPermissionClass" that randomly returns true/false.
Namespace SecurityLibrary
Public MustInherit Class PermissionClass
Public MustOverride Function HasPermission(ByVal permission As String) As Boolean
End Class
Public Class RandomPermissionClass
Inherits PermissionClass
Private rand As New Random()
Public Overrides Function HasPermission(permission As String) As Boolean
Return If(rand.Next(2) = 0, False, True)
End Function
End Class
End Namespace
Now we have the "myControls" library, which contains no references to SecurityLibrary. I created two controls and a delegate. The controls are "PermissionMasterControl" and "PermissionExtender". The delegate is what is used to actually perform the check against the reflected object.
Namespace myControls
Public Delegate Function HasPermissionDelegate(ByVal permission As String) As Boolean
Public Class PermissionMasterControl
Inherits System.Web.UI.Control
Public Property PermissionClass As String
Get
Return If(ViewState("PermissionClass") Is Nothing, "", ViewState("PermissionClass").ToString())
End Get
Set(value As String)
ViewState("PermissionClass") = value
End Set
End Property
Private ReadOnly Property PermissionDelegate As HasPermissionDelegate
Get
If _permissionDel Is Nothing Then
If Not String.IsNullOrEmpty(PermissionClass) Then
Dim t = Type.GetType(PermissionClass, False)
If t IsNot Nothing Then
_permissionObj = Activator.CreateInstance(t)
Dim mi As MethodInfo = _
t.GetMethod("HasPermission", BindingFlags.Public Or BindingFlags.Instance)
_permissionDel = [Delegate].CreateDelegate(GetType(HasPermissionDelegate), _permissionObj, mi)
End If
End If
End If
Return _permissionDel
End Get
End Property
Private _permissionObj As Object = Nothing
Private _permissionDel As HasPermissionDelegate = Nothing
Public Function HasPermission(ByVal permission As String) As Boolean
If PermissionDelegate Is Nothing Then
Throw New NullReferenceException("The specified permission class (" + PermissionClass + ") could not be loaded/found.")
End If
Return PermissionDelegate(permission)
End Function
End Class
Public Class PermissionExtender
Inherits System.Web.UI.Control
Public Property ControlToSet As String
Get
Return If(ViewState("ControlToSet") Is Nothing, "", ViewState("ControlToSet").ToString())
End Get
Set(value As String)
ViewState("ControlToSet") = value
End Set
End Property
Public Property Permission As String
Get
Return If(ViewState("Permission") Is Nothing, "", ViewState("Permission").ToString())
End Get
Set(value As String)
ViewState("Permission") = value
End Set
End Property
Public Property MasterControllerID As String
Get
Return If(ViewState("MasterControllerID") Is Nothing, "", ViewState("MasterControllerID").ToString())
End Get
Set(value As String)
ViewState("MasterControllerID") = value
End Set
End Property
Protected ReadOnly Property MasterController As PermissionMasterControl
Get
If _mastercontroller Is Nothing Then
_mastercontroller = Me.Page.FindControl(MasterControllerID)
End If
Return _mastercontroller
End Get
End Property
Protected ReadOnly Property ManagedControl As Control
Get
If _controlToSet Is Nothing Then
_controlToSet = Me.NamingContainer.FindControl(ControlToSet)
End If
Return _controlToSet
End Get
End Property
Private _controlToSet As Control = Nothing
Private _mastercontroller As PermissionMasterControl = Nothing
Protected Overrides Sub OnLoad(e As System.EventArgs)
MyBase.OnLoad(e)
Dim bResult As Boolean = MasterController.HasPermission(Permission)
ManagedControl.Visible = bResult
End Sub
End Class
End Namespace

User Control validation group issue

I have two instances of a user control on a page. Both have fields and one submit button.
I have set validation groups on the fields and validators but for some reason when validating the two user controls' validators fire.
This method also works:
Dim valGroup = String.format("{0}-validation", Guid.NewGuid())
rfv001.ValidationGroup = valGroup
rfv002.ValidationGroup = valGroup
rfv003.ValidationGroup = valGroup
rfv004.ValidationGroup = valGroup
rfv005.ValidationGroup = valGroup
btnSubmit.ValidationGroup = valGroup
You only need to set the values for the ValidationGroup manually.
You could expose a property ValidationGroup in your UserControl that you would set from the Page. This value should be stored in ViewState, so that every instance of the UserControl will get different ValidationGroups(if your page assigns different).
For example:
Public Property ValidationGroup() As String
Get
Return CStr(ViewState("ValidationGroup"))
End Get
Set(ByVal value As String)
SetValidationGroupOnChildren(Me, value)
ViewState("ValidationGroup") = value
End Set
End Property
Private Sub SetValidationGroupOnChildren(ByVal parent As Control, ByVal validationGroup As String)
For Each ctrl As Control In parent.Controls
If TypeOf ctrl Is BaseValidator Then
CType(ctrl, BaseValidator).ValidationGroup = validationGroup
ElseIf TypeOf ctrl Is IButtonControl Then
CType(ctrl, IButtonControl).ValidationGroup = validationGroup
ElseIf ctrl.HasControls() And ctrl.Visible = True Then
SetValidationGroupOnChildren(ctrl, validationGroup)
End If
Next
End Sub
http://www.craigwardman.com/blog/index.php/2009/05/setting-a-validation-group-on-a-user-control/
http://justgeeks.blogspot.com/2009/09/be-careful-using-hard-coded.html
If you need different ValidationGroups in your UserControl the above recursive function won't work, then you could assign it manually from codebehind. For example by putting the UserControl's ID(might suffice) or ClientID in front of the ValidationGroup properties of the according controls. A good place where you could call this function would be PreRender.

call a vb.net subrouting from a javascript function?

hi folks i have a subroutine called CheckDate() in the code behind.
How would I call that subroutine from a javascript function?
Cheers,
-Jonesy
You can't call it directly as function call.
because Javascript is a scripting langauge aimed for web browsers.
you may use AJAX or full page post sending the parameters to allow you to execute the subroutine.
Read more about Ajax it is the better way to go.
To expand on what Kronass said there I've found this article to be useful in the past for doing what you want http://encosia.com/2008/05/29/using-jquery-to-directly-call-aspnet-ajax-page-methods/. Encosia also has a heap of other blog plots on this if you do a bit of searching
What you're looking to use is normally called a WebMethod, ScriptMethod or Page Method depending on which framework you're using
One way to do this is by using the ICallbackEventHandler interface. I saw you had a question regarding the AjaxControToolkit CalendarExtender the other day so I'm guessing this question is in relation to that and how you do some validation in a server-side method. ICallbackEventHandler is AJAX, but you can write your validation as a normal method, not a PageMethod/WebMethod. It's slightly more fiddly on the Javascript side, but not by much.
Let's start with our basic textbox and calendar extender:
<form id="form1" runat="server">
<asp:ScriptManager runat="server" ID="ScriptManager" />
<div>
<asp:TextBox runat="server" ID="DateTextBox" />
<ajaxtoolkit:CalendarExtender runat="server" ID="CalendarExtender" TargetControlID="DateTextBox"
PopupButtonID="SelectorButton" OnClientDateSelectionChanged="checkDate" Format="dd MMM yyyy" />
<asp:ImageButton runat="server" ID="SelectorButton" ImageUrl="Path to a pretty graphic" />
<br />
<asp:Label runat="server" ID="ValidDateLabel" />
</div>
</form>
I've added the OnDateSelectionChanged attribute of the extender as this will kick off the process of calling the server-side method; we'll come back to what goes in there shortly.
In the class declaration in your code-behind, you need to say that you are implementing the interface:
Partial Public Class _Default
Inherits System.Web.UI.Page
Implements ICallbackEventHandler
To implement the interface we then need to add two more methods to handle the two methods in the interface, RaiseCallbackEvent and GetCallbackResult. We also need a property for a bit of temporary storage of the date we are trying to validate.
Private mCallbackDate As Date
Private Property CallbackDate() As Date
Get
Return mCallbackDate
End Get
Set(ByVal value As Date)
mCallbackDate = value
End Set
End Property
Public Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements ICallbackEventHandler.RaiseCallbackEvent
'eventArgument will contain the date the user selected from the extender
Dim testDate As Date
If eventArgument = String.Empty Then
Else
If Date.TryParse(eventArgument, testDate) Then
'If we have a legal date selected then store it
Me.CallbackDate = testDate
End If
End If
End Sub
Public Function GetCallbackResult() As String Implements ICallbackEventHandler.GetCallbackResult
Dim result As String = String.Empty
'Get the date that we stored in memory and pass it to our CheckDate function
'We'll pass back to the Javascript in the page the string 'true' if the date is
'valid under our business rules and 'false' if it isn't
If checkDate(Me.CallbackDate) Then
Return "true"
Else
Return "false"
End If
End Function
Public Function checkDate(ByVal dateToCheck As Date) As Boolean
'If the date is in the future then return True, otherwise False
If dateToCheck > Date.Today Then
Return True
Else
Return False
End If
End Function
There's one more bit of server-side we need to add, in Page_Load, which does the hooking up of the Javascript and server-side code. The ClientScriptManager's GetCallbackEventReference function will inject a bit of script into our page that takes care of the communication between browser and server. Then we just need to register a script block that calls the injected script - we'll call this function checkDateOnServer.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim callbackScript As String
callbackScript = "function checkDateOnServer(arg){" & _
Page.ClientScript.GetCallbackEventReference(Me, "arg", "receiveDateValidation", "") & _
"}"
ClientScript.RegisterClientScriptBlock(Me.GetType, "callback", callbackScript, True)
End Sub
Back to the client-side bits. We need to write a Javascript checkDate function that'll pass the user's selected date into the callback.
function checkDate()
{
// Get the date the user selected
var selectedDate = document.getElementById('DateTextBox').value;
// This will start the callback sequence
checkDateOnServer(selectedDate);
}
The last bit we need to do is receive the value coming back from the server, which we said in Page_Load would be called receiveDateValidation.
function receiveDateValidation(arg, context)
{
var ValidDateLabel = document.getElementById('SelectedDateLabel');
// We get a string value back from the server which is 'true' or 'false'
if (arg == 'true')
{
ValidDateLabel.innerText = 'Your date IS valid';
}
else
{
ValidDateLabel.innerText = 'Your date IS NOT valid';
}
}

Resources