Makale Özeti

Bu makalemizde, TypeDescriptor sınıfı ile çalışma zamanında gerçekleştirdiğimiz üst veri(metadata) değişiklikleri sayesinde PropertyGrid üzerinde yapabileceğimiz özelleştirmeleri incelemeye çalışacağız.

Makale

    Önceki makalemizde TypeDescriptor sınıfından ve bu sınıfı kullanarak üst veri bilgilerine nasıl erişebileceğimizden bahsetmiştik. Ardından TypeDescriptor ile çalışma zamanında üst veri bilgilerini nasıl değiştirebileceğimize değinmiştik. Bu makalemizde ise  TypeDescriptor yapısını kullanabileceğimiz daha somut bir örnekten bahsetmeye çalışacağız.

    PropertyGrid, Windows Forms uygulamaları geliştirirken sıklıkla kullandığımız bir kontroldür. Visual Studio kullananlar, Form ve kontrollere ait özelliklerin(Property) görüntülendiği Properties penceresini bileceklerdir. PropertyGrid bizlere tam olarak bu özelliği sunmaktadır. PropertyGrid ile nesnelerimizin özelliklerini görüntüleyebilir, üzerinde değişiklikler yapabiliriz. Ayrıca karmaşık nesneleri Form üzerinde birçok kullanıcı kontrolü ile uğraşarak görüntülemek yerine tek bir PropertyGrid kullanarak daha basit ve sade bir görüntüleme ekranı oluşturabiliriz. Bu makaledeki amacımız PropertyGrid kontrolünü tanıtmak olmadığı için bu kontrol hakkında detaylı bilgi vermeyeceğim. PropertyGrid hakkında daha fazla bilgiye ihtiyaç duyanlar MSDN sayfasından ulaşabilirler.

    Şimdi küçük bir örnekle değinmek istediğimiz konuya giriş yapalım:

    Öncelikle Visual Studio içerisinde bir Windows Forms uygulaması oluşturalım. Ardından formumuz üzerinde PropertGrid kontrolünü oluşturacağız. Toolbox’tan PropertyGrid kontrolünü seçip Form üzerine sürükleyelim. Eğer Toolbox üzerinde böyle bir kontrol göremiyorsanız eklemeniz gerecektir. Bunun için Toolbox üzerinde sağ tıkladıktan sonra ChooseItems –> .NET Framework Components adımlarını izleyerek PropertyGird kontrolünü seçebilir ve Toolbox içerisine ekleyebilirsiniz.

PropertyGrid

    Şimdi de PropertyGrid üzerinde görüntüleyeceğimiz sınıfımızı oluşturalım. Bir önceki makalede olduğu gibi Urun sınıfını oluşturuyoruz ve PropertyGrid tarafından kullanılacak gerekli Attribute’ları ekliyoruz:

public class Urun
{
    [Description("Barkod")]
    [ReadOnly(true)]
    public string Barkod { get; set; }
    [Description("Ürün Adı")]
    [ReadOnly(true)]
    public string UrunAdi { get; set; }
    [Description("Ürün Fiyatı")]
    [ReadOnly(true)]
    public double Fiyat { get; set; }
}

    Kod bölümünde de görmüş olduğunuz gibi Property’ler için bazı Attribute sınıfları kullandık. .NET Framework, görüntülenecek verilerin özelleştirilebilmesi için bir dizi Attribute sunmaktadır. Biz burada her Property için DescriptionAttribute ve ReadOnlyAttribute sınıflarını kullandık. Şu anda tüm Property’lerimiz readonly olarak işaretlenmiştir. Diğer bir deyişle; PropertyGrid üzerinde değişiklik yapamayacağız. Şimdi sınıfımızdan yeni bir nesne oluşturarak PropertyGrid üzerinde görüntüleyelim:

private void Form1_Load(object sender, EventArgs e)
{
    Urun u = new Urun { Barkod = "1123211", UrunAdi = "Monitör", Fiyat = 250.25 };
    propertyGrid.SelectedObject = u;
}

    Kodumuzu çalşıtırdığımızda, oluşturduğumuz Urun nesnesini PropertyGrid üzerinde görüyoruz.

propertygridscreen

    Şimdi varsayalım ki; Urun sınıfını ayrı bir kütüphane içerisinden kullanıyoruz ve kodunu değiştirme şansımız yok ancak; PropertyGrid üzerinde görüntülerken Fiyat alanının değiştirilebilir olmasını ve açıklama olarak da “KDV’siz Ürün Fiyatıdır” yazmasını istiyoruz. Bu isteği nasıl gerçekleştirebiliriz? Cevabımız tabiki TypeDescriptor sınıfında saklıdır.

    Öncelikle, Urun sınıfı için bir CustomTypeDescriptor oluşturmamız gerekecektir. Önceki makalemizde bir CustomTypeDescriptor oluşturmuş ve GetProperties() metodunu override etmiştik. PropertyGrid, tipin Property bilgilerine erişirken GetProperties() metodu yerine GetProperties(Attributes[] attribute) metodunu kullanmaktadır. Dolayısıyla, bu örneğimizde GetProperties(Attributes[] attribute) metodunu override etmemiz gerekecektir. Şimdi UrunTypeDescriptor sınıfını oluşturalım:

public class UrunTypeDescriptor : CustomTypeDescriptor
{
    public UrunTypeDescriptor(ICustomTypeDescriptor parent)
        : base(parent)
    {
    }

    public override PropertyDescriptorCollection GetProperties(Attribute[] attr)
    {
        //Tüm property bilgileri getiriliyor
        PropertyDescriptorCollection properties = base.GetProperties(null);
        List<PropertyDescriptor> newProperties = new List<PropertyDescriptor>();
        foreach (PropertyDescriptor prop in properties)
        {
            Attribute[] attributes = null;
            if (prop.Name == "Fiyat")
            {
                //Fiyat isimli property için Attribute bilgilerinde düzenleme yapılıyor.
                attributes = new Attribute[]{
                                     new DescriptionAttribute("KDV'siz fiyat bilgisidir"),
                                     new ReadOnlyAttribute(false)
                                   };
                //Yeni bir PropertDescriptor oluşturularak yeni Attribute bilgileri
                //ve eski PropertyDescriptor ile ilişkilendiriliyor
                newProperties.Add(TypeDescriptor.CreateProperty(typeof(Urun), prop, attributes));
            }
            else
            {
                newProperties.Add(prop);
            }
        }

        return new PropertyDescriptorCollection(newProperties.ToArray());
    }
}

    Yukarıdaki kod bölümünde de gördüğünüz gibi, Fiyat isimli Property için DescriptionAttribute ve ReadOnlyAttribute, istediğimiz kriterlere uygun olacak şekilde yeniden oluşturulmuştur. Diğer Property bilgileri ise olduğu gibi bırakılmıştır.

    Şimdi de Urun sınıfı için bir TypeDescriptionProvider oluşturmamız gerekecektir:

public class UrunTypeDescriptionProvider : TypeDescriptionProvider
{
    public UrunTypeDescriptionProvider(TypeDescriptionProvider parent)
        : base(parent)
    {

    }
    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    {
        ICustomTypeDescriptor desc = base.GetTypeDescriptor(objectType, instance);
        return new UrunTypeDescriptor(desc);
    }

    Artık yapmamız gereken UrunTypeDescriptionProvider sınıfını Urun sınıfı ile ilişkilendirmektedir. Bunu da aşağıdaki şekilde gerçekleştiriyoruz:

TypeDescriptor.AddProvider(new UrunTypeDescriptionProvider(TypeDescriptor.GetProvider(typeof(Urun))), typeof(Urun));

    Şimdi kodumuzu çalıştırabiliriz:

custom_property

    Gördüğünüz gibi artık Fiyat alanınında değişiklik yapabiliyoruz. Ayrıca, açıklama bilgisi de istediğimiz şekilde gözüküyor. Böylelikle, Urun sınıfında hiçbir değişiklik yapmadan, görüntülenen veriler üzerinde düzenleme yapabildik.

    Örneklerde görüldüğü gibi, üst veri bilgilerinde basit değişiklikler yapmaya çalıştım. Ancak; TypeDescriptor yardımı ile istediğiniz düzenlemeleri yapabilir ve PropertyGrid üzerindeki verileri istediğiniz şekilde özelleştirebilirsiniz.

Cemil ABİŞ
http://www.cemilabis.com
http://twitter.com/cemilabis