call a vb.net subrouting from a javascript function? - asp.net

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';
}
}

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

How to apply Client-side validation by calling a server-side function in ASP.NET

I have an ASP.NET Web Forms application.
I have a Form with various TextBoxand right now I have several asp:RequiredFieldValidator linked to them belonging to the same ValidationGroup.
Now I have to apply to some TextBox an additional validation with related error message.
In the specific I got to check whether the text inside the TextBox is a Guid or not. Morevoer this check has to be done on the fly, meaning that as soon as the user moves the cursor from the TextBox the validation has to be performed, without the need to press submit.
How can I call the IsGuid(string guid) function from Javascript?
How can I attach two different error messages as validation (for instance I want to be displayed a message if TextBox.Text has carachters not allowed and lenght < N)
Is it easier to implement this validation with jQuery or with the ASP.NET validators?
If somebody else has any other idea for its implementation, please feel free to propose. Thanks!
You can use ReqularExpressionValidator control.
Here a regex
^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$
You can apply as many Validators as you need to the same control, in this case your TextBox.
In this scenario, a Custom Validator is the way to go because it enables you to do the validation with any function you develop to cover your needs. Please, have a look at this simple tutorial.
UPDATE 1: Server Side Validation
This is how it calls the server side function in the declaration of the CustomValidator:
<asp:CustomValidator runat="server" id="custPrimeCheck"
ControlToValidate="txtPrimeNumber"
OnServerValidate="PrimeNumberCheck"
ErrorMessage="Invalid Prime Number" />
Example of the "PrimeNumberCheck" VB function:
Sub PrimeNumberCheck(sender as Object, args as ServerValidateEventArgs)
Dim iPrime as Integer = Cint(args.Value), iLoop as Integer, _
iSqrt as Integer = CInt(Math.Sqrt(iPrime))
For iLoop = 2 to iSqrt
If iPrime mod iLoop = 0 then
args.IsValid = False
Exit Sub
End If
Next
args.IsValid = True
End Sub
UPDATE 2: Client Side Validation
This is how it calls the server side function in the declaration of the CustomValidator:
<asp:CustomValidator runat="server" id="custPrimeCheck"
ControlToValidate="txtPrimeNumber"
ClientValidationFunction="CheckPrime"
ErrorMessage="Invalid Prime Number" />
Example of the "CheckPrime" JavaScript function:
function CheckPrime(sender, args)
{
var iPrime = parseInt(args.Value);
var iSqrt = parseInt(Math.sqrt(iPrime));
for (var iLoop=2; iLoop<=iSqrt; iLoop++)
if (iPrime % iLoop == 0)
{
args.IsValid = false;
return;
}
args.IsValid = true;
}
Thanks to #AdrianIftode for making me aware of this.

Stumped With Custom Property on User Control

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.

ASP.NET Server Control - Is shared Viewstate between controls possible

If I have a master 'composite custom server control', with several child custom controls, is it possible, for the master control to share its viewstate with the child controls, which are also custom composite server controls,(all of the controls are composite custom server controls)?
To expand a little more, say I have a Person control, Address control, Phone control and Notes control. Address, Phone and Notes can exist as either independant controls, or as part of the Person control. Since each control is responsible for its own viewstate, and stores required data in it, so it can render/postback etc, it ends up that there is a lage duplication in the viewstate, since the Person control stores all the data, and then each child control stores its own data again. Also, to further complicate things, the Person Control adds the child controls dynamically, so its possible to add a 2nd address/phone number/note etc,which can cause yet a larger viewstate(up to 1MB).
In the case of when all the Address/Phone/etc controls are children of the the Person Control, is it possible for me to somehow share common viewstate data, so I dont have 2/3/4 copies of some stuff in the viewstate, and when they are not components, just act as normal?
I do have one idea for a solution, but its fairly nasty imo, where I could modify the Person control, expose its viewstate or the data, and then in the child control, would check the control hierarchy, and if the child control is part of a Person, dont use to its own viewstate, use the exposed one. This would require me to rework alot of the existing code, which I'd rather avoid if possible.
The first question I'd ask is, "How much of this data do you really need to keep on the ViewState?" For example, is there enough information in a typical page request to be able to rebuild all of the information that is in some of these controls?
I find that ASP.NET typically uses ViewState far more than I really need it to, and if you're getting a 1MB viewstate, I suspect the same is probably true for you. I highly recommend reading this article to get a more full understanding of how ViewState works, what causes values to get saved to ViewState, and how to avoid using it where it's not necessary. You may be able to solve the bulk of your problem simply by doing more of your work in Page_Init instead of Page_Load, for example.
You can "share" a ViewState between any number of objects by passing it around as a StateBag type, or by using delegate functions that return the ViewState that needs to be shared. The usage of this, however; should be limited to very specific circumstances, because typically controls use Properties to expose their ViewState data to other objects (See the link #StriplingWarrior posted here). That being said, here is some example code:
User Control: SharedState.ascx
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="SharedState.ascx.vb" Inherits="TestSite.SharedState" %>
User Control: SharedState.ascx.vb
Public Class SharedState
Inherits System.Web.UI.UserControl
Public Delegate Function GetStateDelegate() As StateBag
Public Const SharedValueKey = "The key used to access the ViewState dictionary"
Public Property GetState() As GetStateDelegate
' Different ways to get values
Public Function GetTypedValue(Of TValue)() As TValue
Return CTypeDynamic(GetValue(), GetType(TValue))
End Function
Public Function GetValue() As Object
' Use the delegate to get the view state from the parent
Return GetState.Invoke()(SharedValueKey)
End Function
Public Function GetValue(state As StateBag) As Object
Return state(SharedValueKey)
End Function
' Different ways to set values
Public Sub SetTypedValue(Of TValue)(value As TValue)
Me.SetValue(value)
End Sub
Public Sub SetValue(value As Object)
GetState.Invoke()(SharedValueKey) = value
End Sub
Public Sub SetValue(state As StateBag, value As Object)
state(SharedValueKey) = value
End Sub
' Set ViewState value using a key and the delegate
Public Sub SetStateWithKey(key As String, value As Object)
GetState.Invoke()(key) = value
End Sub
' Get ViewState value using a key and the delegate
Public Function GetStateWithKey(key As String) As Object
Return GetState.Invoke()(key)
End Function
End Class
Page: SharedStatePage.aspx
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="SharedStatePage.aspx.vb" Inherits="TestSite.SharedStatePage" %>
<%# Register src="SharedState.ascx" tagname="SharedState" tagprefix="uc1" %>
<uc1:SharedState ID="SharedState1" runat="server" />
<uc1:SharedState ID="SharedState2" runat="server" />
Page: SharedStatePage.aspx.vb
Public Class SharedStatePage
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' Set up SharedState 1 & 2 to use the delegate '
SharedState1.GetState = AddressOf GetState
SharedState2.GetState = AddressOf GetState
' Set the view state from the page '
ViewState(SharedState.SharedValueKey) = 23
' Read the view state from the user controls '
Dim sharedInt As Integer
sharedInt = SharedState1.GetTypedValue(Of Integer)()
sharedInt = SharedState1.GetValue()
sharedInt = SharedState1.GetValue(ViewState)
sharedInt = SharedState2.GetValue()
' Set the view state from one of the user controls '
SharedState2.SetTypedValue(Of String)("Hello")
Dim sharedStr As String = ViewState(SharedState.SharedValueKey)
sharedStr = SharedState1.GetTypedValue(Of String)()
sharedStr = SharedState2.GetValue()
' Use a different key to set and get view state data '
ViewState("MyKey") = New With {.Name = "Some Object", .Value = 46}
Dim myObj = SharedState1.GetStateWithKey("MyKey")
SharedState2.SetStateWithKey("MyKey", "New Value")
myObj = ViewState("MyKey")
End Sub
Private Function GetState() As StateBag
Return ViewState
End Function
End Class
Use with caution, or don't use with abandon.

On postback, how can I add a error message to validation summary?

Two questions:
On postback when a user clicks submit, how can I add a error message to validation summary?
Is it also possible to highlight a particular textbox using the built in .net validation controls?
Dynamically create a CustomValidator control and add it directly to the Page.Validators collection.
Dim err As New CustomValidator
err.ValidationGroup = "MyGroup"
err.IsValid = False
err.ErrorMessage = "The password is invalid"
Page.Validators.Add(err)
Unlike adding the CustomValidator to the markup, this method allows you to add any number of arbitrary error messages based on server-side business logic.
Note that you can also add it to the page directly, but there are a couple of rules to follow:
You must add the control to the same naming container as the controls of the validation group.
If you don't want the validation message to appear in a random position in the page, you will either have to add the validator to a specific container or you will need to supress it using a CSS class or style.
You can also create a custom class and implement IValidator, which enables you to add the message with one line of code, but this method doesn't support Validation Groups.
Per Anders Fjeldstad's suggestion, here are a set of handy extension methods.
Imports Microsoft.VisualBasic
Imports System.Runtime.CompilerServices
Public Module PageExtensions
<Extension()> _
Public Sub AddValidationError(ByVal p As System.Web.UI.Page, ByVal errorMessage As String)
p.AddValidationError(errorMessage, String.Empty)
End Sub
<Extension()> _
Public Sub AddValidationError(ByVal p As System.Web.UI.Page, ByVal errorMessage As String, ByVal validationGroup As String)
Dim err As New CustomValidator
err.ValidationGroup = validationGroup
err.ErrorMessage = errorMessage
err.IsValid = False
p.Validators.Add(err)
End Sub
End Module
Add a custom validator and manually set it's IsValid and ErrorMessage properties. Sort of like this:
<asp:panel ID="ErrorsPanel" runat="server" CssClass="ErrorSummary">
<asp:CustomValidator id="CustomValidator1" runat="server"
Display="None" EnableClientScript="False"></asp:CustomValidator>
<asp:ValidationSummary id="ErrorSummary" runat="server"
HeaderText="Errors occurred:"></asp:ValidationSummary>
</asp:panel>
In the code behind:
//
// Update the database with the changes
//
string ErrorDetails;
if (!Db.Update(out ErrorDetails))
{
CustomValidator1.IsValid = false;
CustomValidator1.ErrorMessage = ErrorDetails;
}
Here's a little extension to the good idea from NightOwl888:
public class ValidationError : CustomValidator
{
public ValidationError(string group, string msg)
: base()
{
base.ValidationGroup = group;
base.ErrorMessage = msg;
base.IsValid = false;
}
}
public static class PageExtensions
{
public static void ErrorMessage(this Page page, string group, string msg)
{
page.Validators.Add(new ValidationError(group, msg));
}
}
Whenever you want to issue an error message, simply call Page.ErrorMessage; the mechanism is the same as he suggested.
Well all you need to do is create a Custom Validator and add it to the Validator collection of your page, whenever the condition to do so arises.
CustomValidator cv = new CustomValidator();
if(condition)
{
cv.IsValid = false;
cv.ErrorMessage = "This Catalog Data already exists.";
cv.ValidationGroup = "InputList";
this.Page.Validators.Add(cv);
}
NOTE: Dont forget to specify the ValidationGroup, or the error message is not going to be displayed inspite of the custom validator being added to your page. And ya, if you do get an answer to your 2nd question(highlighting textbox) do post it!
To add error message on validation summary you can use EnableClientScript property of ValidationSummary and the other validation controls. Set EnableClientScript to false all of them :
<asp:ValidationSummary
HeaderText="You must enter a value in the following fields :"
DisplayMode="BulletList"
EnableClientScript="false"
runat="server"/>
For highlighting a control, no it's not possible with current controls.
But I put my validation controls near the related controls, and I set their Text property as "*". Then if the validation fails, it appears near failed control.
Maybe you can use custom validator to highlight the failed control. But you should write your own implementation.
Here is a version of the above answers that is an extension method for ValidationSummary, which takes care of the validation group ID.
public static void AddCustomMessage(this ValidationSummary summaryControl, string message)
{
summaryControl.Page.Validators.Add(new CustomValidator {
ValidationGroup = summaryControl.ValidationGroup,
ErrorMessage = message,
IsValid = false
});
}

Resources