"Hát a Text property-t, nem?" Na ennyire nem egyszerű a helyzet, de kezdjük inkább az elején. Ha írunk egy saját kontrollt, majd feldobunk belőle egy példányt az egyik WebFormunkra, majd mellérakunk például egy RequiredFieldValidatort, akkor futtatáskor először a következő hibaüzenetet fogjuk kapni:
The ControlToValidate property of 'rfvPhone' cannot be blank.
Nincs semmi meglepetés, mindenki tudja, hogy a ControlToValidate tulajdonságot be kell állítani, mégis mindenki elfelejti az első fordítás előtt ;-) Amikor azonban megpróbáljuk beállítani ennek a tulajdonságnak az értékét, csalódottan fogjuk tapasztalni, hogy a Studioban a Properties ablakban nem tudjuk kiválasztani a saját vezérlőnket. Ne adjuk fel, bátran írjuk be a nevét mezőbe! Következő futtatás, következő hibaüzenet:
Control 'ctrlPhone' referenced by the ControlToValidate property of 'rfvPhone' cannot be validated.
Na, itt már valami gond van, nem lehet validálni a kontrollunkat. Idézzük fel, mit tanultunk a validátorokról: ha sajátot akarunk írni, akkor a BaseValidatorból kell származtatni kell és felül kell definiálni az EvaluateIsValid metódust. Nézzük mit találunk ebben, ha a RequiredFieldValidator az alany:
protected override bool EvaluateIsValid()
{
string controlValidationValue = base.GetControlValidationValue( base.ControlToValidate );
return ( ( controlValidationValue == null ) ||
!controlValidationValue.Trim().Equals( this.InitialValue.Trim() ) );
}
Az a bizonyos kutya tehát a BaseValidator osztály GetControlValidationValue metódusában van elásva, hantoljuk ki:
protected string GetControlValidationValue( string name )
{
Control component = this.NamingContainer.FindControl( name );
if( component == null )
{
return null;
}
PropertyDescriptor validationProperty = GetValidationProperty( component );
if( validationProperty == null )
{
return null;
}
object obj2 = validationProperty.GetValue( component );
if( obj2 is ListItem )
{
return ( (ListItem) obj2 ).Value;
}
if( obj2 != null )
{
return obj2.ToString();
}
return string.Empty;
}
Tehát valahogy megszerezzük a tulajdonságot és elkérjük az értékét. Ha az érték típusa ListItem, akkor annak a Value tulajdonsága a fontos, egyébként egyszerűen megToStringezzük. Ebből tehát az következik, hogy bármilyen típusú tulajdonságot lehet validálni, hiszen ToString metódusa mindennek van.
Hogyan lesz meg a validálandó tulajdonság? A legelső sorban megkeressük magát a kontrollt. Itt érdemes megfigyelni, hogy csak az aktuális naming containeren belül keresünk, ezért kell a validátort a kontroll "közelébe" tenni. A keresett tulajdonságot a BaseValidator GetValidationProperty metódusa adja vissza, mégpedig így:
public static PropertyDescriptor GetValidationProperty( object component )
{
ValidationPropertyAttribute attribute =
(ValidationPropertyAttribute) TypeDescriptor.GetAttributes( component )[
typeof( ValidationPropertyAttribute ) ];
if( ( attribute != null ) && ( attribute.Name != null ) )
{
return TypeDescriptor.GetProperties( component, (Attribute[]) null )[ attribute.Name ];
}
return null;
}
Keressük tehát azt a tulajdonságot, amelyet az osztályhoz rendelt ValidationPropertyAttribute Name tulajdonsága meghatároz. Magyarul nem csak a Text property-t lehet validálni, hanem bármit, csak mondjuk meg szegény validátornak, mégpedig a kontrollunkhoz rendelt attribútummal:
[ValidationProperty( "LocalNumber" )]
public partial class PhoneControl : System.Web.UI.UserControl
{...}
Ha ezt megtesszük, eltűnik a hibaüzenet, a kontrollunkhoz már nyugodt szívvel tehetünk validátorokat. Ennek az attribútumnak egyébként a következő a szintaxisa az MSDN-ben:
[AttributeUsageAttribute( AttributeTargets.Class )]
public sealed class ValidationPropertyAttribute : Attribute
Mivel az attribútumot osztályhoz rendeljünk és nem lehet több példányban felhasználni, csak egy tulajdonságot validálhatunk. Ha mégis megpróbáljuk többszörösen használni, fordítási hibát kapunk:
error CS0579: Duplicate 'ValidationProperty' attribute
Ezek után joggal merül fel a kérdés, vajon a Properties ablak is ez alapján dolgozik? Reflectorral megnézve a BaseValidator ControlToValidate tulajdonságát azt vehetjük észre, hogy egy ValidatedControlConverternevű TypeConverter van hozzárendelve, aminek a FilterControl metódusát a következőképpen implementálták:
protected override bool FilterControl( Control control )
{
ValidationPropertyAttribute attribute =
(ValidationPropertyAttribute) TypeDescriptor.GetAttributes( control )[
typeof( ValidationPropertyAttribute ) ];
if( attribute != null )
{
return ( attribute.Name != null );
}
return false;
}
Tehát azok a kontrollok fognak kiválaszthatóként megjelenni a Properties ablakban a ControlToValidate tulajdonságnál, amelyekhez van ilyen attribútum és annak a Name tulajdonsága is meg van adva. Reflectorral keresgélve a következő típusokat és validálandó tulajdonságaikat találtam:
- HtmlInputFile: Value
- HtmlInputPassword: Value
- HtmlInputText: Value
- HtmlSelect: Value
- HtmlTextArea: Value
- DropDownList: SelectedItem
- FileUpload: FileName
- ListBox: SelectedItem
- RadioButtonList: SelectedItem
- TextBox: Text
Na, ezért nem tudunk validátort tenni egy CheckBoxListre, amikor rá akarjuk kényszeríteni a felhasználót, hogy legalább egy elemet válasszon ki.
Ennyi tudással felvértezve visszemehetünk a Properties ablakba és megnézhetjük, hogy már ki lehet-e választani a saját kontrollunkat a validálandó kontrollok listájából, majd joggal kérdezhetjük, hogy miért nem? Aki tudja, kérem írja meg. Köszönöm!