"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!