Makale Özeti

IExtenderProvider Interface'i ile Windows Forms TextBox Validator

Makale

IExtenderProvider Interface’i ile Windows Forms TextBox Validator

IExtenderProvider

Bir Extender ile diğer bileşenlere özellikler eklenebilir. IExtenderProvider arayüzü ise bir extender geliştirmek için gerekli olan arayüzü sunmaktadır.

Hemen somut bir örnek ile konunun daha rahat anlaşılmasını sağlayacak olursak; Windows Form geliştirirken kullanılan ToolTip bileşenine işaret edebiliriz.


ToolTip Kontrolü

ToolTip kontrolü form üzerine sürüklediğinizde görsel niteliği olmayan bir component olduğu için form altında yer alan bölümde gözükür ve ekranda yer alan kontrollere birer ToolTip özelliği ekler. Aşağıdaki resimde gözükmekte olduğu gibi Email girişi yapılacak olan textbox kontrolü seçildiğinde Properties ekranında ToolTip on toolTip1 şeklinde bir özellikle belirmektedir. Bu özellik form üzerinde toolTip1 kontrolü silindiğinde gözükmemektedir.

Extender kontroller eklenen yeni özellikleri ve bağlı olan işlevleri yine kendisi gerçekleştirir ancak form tasarım ekranı üzerinde istenilen tüm kontrollere ek özellikler ekleyerek tasarım çalışılabilmeyi sağlar.

using System;

namespace System.ComponentModel

{

public interface IExtenderProvider

{

bool CanExtend(object extendee);

}

}

IExtenderProvider Interface'i yukarıdaki örnek kod bloğunda gözüktüğü gibi System.ComponentModel namespace'i altında yer almaktadır ve CanExtend metodunu implemente etmemizi zorunlu kılar.

Form designer, form üzerinde yer alan bir kontrolün extend edilip edilemeyeceğini CanExtend metodunu çağırarak öğrenir.

IExtenderProvider interface'ini kullanarak form üzerinde yer alan TextBox kontrollerinden veri girişi zorunlu olanları belirleyebileceğimiz bir validator kontrolü geliştirelim.

TextBox Validator Örneği

Validator adında bir sınıf oluşturalım ve Component sınıfından miras almasını sağlayarak form designer üzerine eklenmesini sağlayalım, IExtenderProvider arayüzünü uygulamasını sağlayarak form üzerindeki diğer bileşenlere özellikler eklemesini sağlayalım.

IExtenderProvier arayüzü dolayısıyla CanExtend metodunu uyguluyoruz burada tek koşulumuz bileşenin TextBox sınıfı türünde olmasıdır zira bu örnekteki extender'in amacı TextBox lara ek birer özellik eklemektir.

using System;

using System.Collections.Generic;

using System.Text;

using System.ComponentModel;

using System.Windows.Forms;

using System.Collections;

 

namespace ValidationExtender

{

    public class Validator : Component, IExtenderProvider

    {

        #region IExtenderProvider Members

        /// <summary>

        /// Form designer form üzerinde yer alan bir kontrolün

        /// extend edilip edilemeyeceğini bu metodu çağırarak öğrenir.

        /// Bu örnekte herhangi bir TextBox olması yeterli. Özel bir şart yok.

        /// </summary>

        /// <param name="extendee"></param>

        /// <returns></returns>

        public bool CanExtend(object extendee)

        {

            return (extendee is TextBox);

        }

        #endregion

 

    }

}

Ancak diğer kontrollere özellikler eklemek için yapılması gerekenler vardır.

ProvideProperty attribute

Bu attribute ile bu extender kontrolünün hangi tipte bileşenlere hangi özellikleri ekleneceği belirlenir. Bu örneğimizde TextBox kontrollerine AllowNull adında bir özellik ekleneceği için Validator sınıfına ProvideProperty niteliği aşağıdaki şekilde eklenmelidir.

[ProvideProperty("AllowNull", typeof(TextBox))]

ProvideProperty niteliği ile belirlenen property isminin önüne Get ve Set  ifadeleri eklenmiş methodların Validator sınıfına eklenmesi birer zorunluluktur.

Bu methodlar ile belirlenen kontrol için değer atama ve değer okuma işlemleri yapılacaktır. Metodların imzası aşağıdaki gibi olmalıdır

Set methodunun birinci parametresi AllowNull değeri belirlenecek metodu alır. İkinci parametre ise değeir alır.

public void SetAllowNull(TextBox textBox, bool AllowNull)

public bool GetAllowNull(TextBox textBox)

Set metodunun ikinci parametresinde ve Get methodunun dönüş türü olarak bool veri türünün seçilmesi sayesinde designer üzerinde properties ekranın nasıl şekilleneceği belirlenir. Bu durumda properties ekranı yazılım geliştiriciye True/False seçeneğini sunmaktadır.

      #region AllowNull Methodları

        /// <summary>

        /// AllowNull özelliğine değer atamak için kullanılan method.

        /// </summary>

        /// <param name="textBox">AllowNull özelliği belirlenecek olan textbox kontrolü.</param>

        /// <param name="AllowNull">Kontrolün AllowNull özelliği için değeri</param>

        public void SetAllowNull(TextBox textBox, bool AllowNull)

        {

            extendeeList[textBox] = AllowNull;

        }

        /// <summary>

        /// TextBox kontrolünün AllowNull özelliğinin değerini dönen method.

        /// </summary>

        /// <param name="textBox">AlllowNull özelliği öğrenilecek olan TextBox kontrolü</param>

        /// <returns>true/false olarak AllowNull değerini döner.</returns>

        public bool GetAllowNull(TextBox textBox)

        {

            bool result = true;

            if (extendeeList.Contains(textBox))

            {

                result = (bool)extendeeList[textBox];

            }

            return result;

        }

        #endregion

Yukarıdaki kod bloğu incelendiğinde her kontrolün değerinin bir Hashtable (extendeeList) içinde key olarak TextBox kontrolü, value olarak AllowNull bool değerinin tutulduğu gözükmektedir. Burada amacımız sadece değeri tutmak olduğu için Hashtable üzerindeki değerleri yönetiyoruz ancak kontrollerin bazı eventlarına kayıt olmak ve eventları handle etmek gibi işlemlerde genelde uygulanan pratiklerdendir.

Bu noktaya kadar her kontrolün AllowNull özelliği var. Validator kontrolümüzü Toolbox'dan form üzerine sürükleyerek bir örneğini ekleyelim.

Validator kontrolünü form üzerine eklediğimize göre Bunlar form designer tarafından oluşturulan kod bloğunda aşağıdaki şekil ve kod bloğunda gözüktüğü gibidir.

 

Bu noktaya kadar form üzerindeki TextBox kontrollerimize validation amaçlı AllowNull özelliğini eklemiş bulunuyoruz. Şimdi bunların doğrulanması işlemini gerçekleştirelim. Bu görevi Extender amacı ile oluşturduğumuz Validator sınıfına vermemiz en mantıklı çözüm olarak gözükmektedir.

Aşağıdaki kod bloğunda Validator sınıfımızın bitmiş hali bulunmaktadır. "Validator Form Methodları" adındaki region içinde textbox kontrollerinin durumlarına göre sonuç veren metod ve özellikleri bulunmaktadır.

 

using System;

using System.Collections.Generic;

using System.Text;

using System.ComponentModel;

using System.Windows.Forms;

using System.Collections;

 

namespace ValidationExtender

{

    [ProvideProperty("AllowNull", typeof(TextBox))]

    public class Validator : Component, IExtenderProvider

    {

        private Hashtable extendeeList;

 

        public Validator()

        {

            extendeeList = new Hashtable();

        }

 

        #region IExtenderProvider Members

        /// <summary>

        /// Form designer form üzerinde yer alan bir kontrolün

        /// extend edilip edilemeyeceğini bu metodu çağırarak öğrenir.

        /// Bu örnekte herhangi bir TextBox olması yeterli. Özel bir şart yok.

        /// </summary>

        /// <param name="extendee"></param>

        /// <returns></returns>

        public bool CanExtend(object extendee)

        {

            return (extendee is TextBox);

        }

        #endregion

 

        #region AllowNull Methodları

        /// <summary>

        /// AllowNull özelliğine değer atamak için kullanılan method.

        /// </summary>

        /// <param name="textBox">AllowNull özelliği belirlenecek olan textbox kontrolü.</param>

        /// <param name="AllowNull">Kontrolün AllowNull özelliği için değeri</param>

        public void SetAllowNull(TextBox textBox, bool AllowNull)

        {

            extendeeList[textBox] = AllowNull;

        }

        /// <summary>

        /// TextBox kontrolünün AllowNull özelliğinin değerini dönen method.

        /// </summary>

        /// <param name="textBox">AlllowNull özelliği öğrenilecek olan TextBox kontrolü</param>

        /// <returns>true/false olarak AllowNull değerini döner.</returns>

        public bool GetAllowNull(TextBox textBox)

        {

            bool result = true;

            if (extendeeList.Contains(textBox))

            {

                result = (bool)extendeeList[textBox];

            }

            return result;

        }

        #endregion

 

 

        #region Validator Form Methodları

        private string _ErrorMessageTemplate = "{0} alanına veri girişi zorunludur.";

        private List<TextBox> _NotValidTextBoxList;

        /// <summary>

        /// Kontrollere veri girilmesinin zorunlu olduğunu bildiren hata mesajı. {0} kontrolün adını ekler.

        /// </summary>

        public string ErrorMessageTemplate

        {

            get { return _ErrorMessageTemplate; }

            set { _ErrorMessageTemplate = value; }

        }

        /// <summary>

        /// ValidateForm methodunda false dönmesi durumunda hangi TextBox kontrollerinin girdilerinin geçerli olmadığını döner.

        /// </summary>

        [Browsable(false)]

        public List<TextBox> NotValidTextBoxList

        {

            get

            {

                return _NotValidTextBoxList;

            }

        }

        /// <summary>

        /// Validatorın üzerine yer aldığı formun validation durumunu dönen method..

        /// </summary>

        /// <returns>Formun üzerinde zorunlu olan alanların girilip girilmediğine göre true/false döner.</returns>

        public bool ValidateForm()

        {

            _NotValidTextBoxList = new List<TextBox>();

            foreach (DictionaryEntry dict in extendeeList)

            {

                bool AllowNull = (bool)dict.Value;

                if (!AllowNull)

                {

                    TextBox txt = (TextBox)dict.Key;

                    if (!IsValidTextBox(txt))

                    {

                        NotValidTextBoxList.Add(txt);

                    }

                }

            }

            return NotValidTextBoxList.Count == 0;

        }

 

        private bool IsValidTextBox(TextBox txt)

        {

            return !string.IsNullOrEmpty(txt.Text.Trim());

        }

        [Browsable(false)]

        public string ErrorMessage

        {

            get

            {

                StringBuilder sbErrorMessage = new StringBuilder();

                foreach (TextBox txt in NotValidTextBoxList)

                {

                    sbErrorMessage.Append(string.Format(this.ErrorMessageTemplate, txt.Name));

                    sbErrorMessage.Append("\n");

                }

                return sbErrorMessage.ToString();

            }

        }

        #endregion

    }

}

Validator sınıfımızda gerekli method ve özellikleri yazdığımıza göre sırada bu extenderın form üzerine test edilip kullanılması var. 

Bunun için daha önce oluşturuduğumuz formu kullanmaya devam edeceğiz. Formda yer alan Kaydet butonunun Click eventine aşağıdaki kod bloğunu yazalım.

Validator kontrolünün ErrorMessageTemplate değerini varsayılan değeri ile bırakıyoruz.

Ad ve Email alanlarının girileceği metin kutularını zorunlu alan olarak belirliyoruz. Soyad alanın AllowNull değerini True olarak bırakıp veri girişini zorunlu yapmıyoruz.

        private void btnOK_Click(object sender, EventArgs e)

        {

            bool isValid = validator1.ValidateForm();

            if (!isValid)

            {

                MessageBox.Show(validator1.ErrorMessage, "veri girişi zorunlu alan"); ;

            }

        }

ValidateForm metodu ile geriye dönen sonuca göre zorunlu alanlar ile ilgili mesaj kutusunu gösteriyoruz.

 

Buradaki hata mesajında kullanıcıya form üzerindeki programatik isimleri ile hata mesajı getirildiği gözükmektedir.

Bunun için neler yapılması gerekenler işlemler, kontrollere UserFriendlyName gibi bir özellik ekleyip, daha sonra hata mesajında bu eklenmiş özelliği kullanmak olacaktır.

Bunun için ilk adım olarak sınıfımıza ProvideProperty niteliği ile UserFriendlyName özelliğini eklettirelim.
Sınıfa yapılan eklemeler kalın olarak gösterilmiştir.

    [ProvideProperty("AllowNull", typeof(TextBox))]

    [ProvideProperty("UserFriendlyName", typeof(TextBox))]

    public class Validator : Component, IExtenderProvider
    {

        private Hashtable extendeeList;

        private Hashtable userFriendlyNameList;

 

        public Validator()

        {

            extendeeList = new Hashtable();

            userFriendlyNameList = new Hashtable();

        } 

....

....

....

 

        #region UserFriendlyName Methodları

        public void SetUserFriendlyName(TextBox textBox, string UserFriendlyName)

        {

            userFriendlyNameList[textBox] = UserFriendlyName;

        }

        public string GetUserFriendlyName(TextBox textBox)

        {

            string result = textBox.Name;

            if (userFriendlyNameList.Contains(textBox))

            {

                result = (string)userFriendlyNameList[textBox];

            }

            return result;

        }

        #endregion

 

 

 

Bu eklemelerden sonra ErrorMessage propertysinde yer alan ilgili satırı kontrolün ismini değil UserFriendlyName değerini alacak şekilde düzenleyelim.

 

        public string ErrorMessage

        {

            get

            {

                StringBuilder sbErrorMessage = new StringBuilder();

                foreach (TextBox txt in NotValidTextBoxList)

                {

                    sbErrorMessage.Append(string.Format(this.ErrorMessageTemplate, this.GetUserFriendlyName(txt)));

                    sbErrorMessage.Append("\n");

                }

                return sbErrorMessage.ToString();

            }

        }

 

txt.Name ifadesi yerine GetUserFriendlyName metodunu kullanarak kullanıcıya gösterilecek metni belirlemiş oluyoruz.

 

Bu özellik form designer üzerinde aşağıdaki şekilde gözükmektedir ve form tasarımı yapan yazılım geliştirici tarafında belirlenmelidir.

 

 

Ad ve soyad textbox kontrolleri içinde UserFriendlyName değerini belirledikten sonra aynı AllowNull değerleri ile formu tekrar çalıştırıp hiç veri girişi yapmadan Kaydet butonuna bastığımızda aldığımız hata mesajı aşağıdaki şekilde olacaktır.

 

 

Kaydet butonuna tıklandığında isValid değerine göre istediğiniz işlemi yapmak (girdileri veritabanına kaydetmek gibi) yada yapmamak tamamen sizin içinde bulunduğunuz duruma bağlıdır.

 

Makalenin ana konusu olmasa da bu validator kontrolünün geliştirilmeyi bekleyen bazı noktaları vardır. TextBox dışında kontrollerin tanınması ve uygun veri türü kontrolü (sadece rakamsal değerler girilmesi gibi), regex kalıbı gibi kontrollerinde eklenmesi validator kontrolünü tam fonksiyonel hale getirecektir.

 

Bu örnek gerçek hayatta işinize yarayacak bir windows forms validator kontrolü için ilk adımlarını atarak ile IExtenderProvider arayüzü ile neler yapılabileceğini inceledik.

 

Cengiz HAN

Microsoft MVP

cengiz@cengizhan.com