25 Şubat 2011 Cuma

Nested (İçiçe) DataList

Web uygulamalarında veri gösterme kontrollerinden daha önce bahsetmiştik. Veritabanından, xml'den ...vs. bilgiler geldiği zaman, bu bilgileri, bahsettiğimiz veri gösterme kontrollerinden gösteriyoruz. DataList, GridView, Repeater vs. kullanıyoruz. Çoğu zaman tek bir kontrolle tüm bu bilgileri gösterebiliyoruz.


Senaryomuz gereği, bir kullanıcı birden fazla eğitim bilgilerine sahipse, ve bu eğitim bilgileri database'den birden fazla satır halinde geliyorsa, ne yapmamız gerekir?


İşte burada yardımımıza nested datalist giriyor. DataList içindeki ItemTemplate'ine bir datalist daha oluşturursak, her eğitim bilgisi için, ikinci yazdığımız DataList çalışacak ve biz eğitim bilgilerini datasource olarak verdiğimiz taktirde, her itemtemplate'de datalist çalışacak ve eğitim bilgileri birden fazla da olsa gösterilecek.


Kodlamaya gelirsek, ana düşüncemiz, dışardaki DataList için bir kaynak vermek olmalı ve daha sonra da ItemDataBound isimli eventini tetiklemek olmalı. Peki ne işe yarıyor bu event? ItemDataBound eventi, verileri ekrana yazmadan onlara erişmemizi sağlayan, bir takım işlemleri yapmamıza olanak sağlayan eventtir. Örneğin labellardan bazılarının visible'ını false yapmak. Veya kendi örneğimizden içerdeki diğer datalist'lere erişip, onlara datasource vererek çalışmalarını sağlamak vs..


Önce PageLoad'da en dıştaki DataList'imize veri kaynağı gösterelim.


public partial class _Default : System.Web.UI.Page
{
   if (!IsPostBack)
       {
    a = 0;
    id = Request.QueryString["UserID"].ToString();
    string query = "select * from XTable";
    DataTable dt = VerTabanından dönen sonuç
    dlResult.DataSource = dt;
    dlResult.DataBind();
        }
 }


protected void dlResult_ItemDataBound(object sender, DataListItemEventArgs e)
{       
   if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
   DataList dlPersonal =(DataList)e.Item.FindControl("dlPersonal");
   DataList dlEducation =(DataList)e.Item.FindControl("dlEducation");
   DataList dlJobExp = (DataList)e.Item.FindControl("dlJobExp");

   dlPersonal.DataSource = Verikaynağı 1
   dlEducation.DataSource = Verikaynağı 2
   dlJobExp.DataSource = Verikaynağı 3
   dlJobExp.DataBind();
   dlEducation.DataBind();
   dlPersonal.DataBind();           
}
}

Yukarıdaki kodlarda açıklama yapmak gerekirse, dlResult_ItemDataBound eventi, tam dlResult.DataBind() çalıştıktan sonra tetiklenir. Eventin içerisine girdiğimizde, bir kontrol yapmamız gerekir. Bu kontrol, DataList'in içinde footer,header,seperator,item, ve alternating template bulunduğundan, her bir template için bir kere çalışacaktır bu event. Dolayısıyla bizim, sadece item template ve alternating template için çalışmasını istediğimizden bu kontrolü koyuyoruz. Daha sonra bu DataList içindeki DataList'lere erişmek için FindControl metodu yardımıyla DataListlerimize erişip, onlara datasourcelarını veriyoruz. Ben burada, DataList içerisindeki labelların text'lerini Eval yardımıyla doldurdum, istersek içerdeki DataListlerin de ItemDataBound eventini tetikleyip, o datalistlerin içindeki labelları bulup, text'lerini değiştirebilirdik. Eval daha kısa ve mantıklı kullanış olacaktır.


Buradaki senaryo, DataList üzerinden gerçekleşti fakat, aynı event, aynı mantık GridView ve repeater için de geçerli. Sadece ufak birkaç kod değişikliği olacaktır. Onlar da kontrollere erişme kısmında olacaktır. Önemli olan mantığı oturtmak ki, bu örnekteki düşünce yapısıyla rahatlıkla yapılacaktır. 

16 Şubat 2011 Çarşamba

Xml'de Karakter Sorunu

Xml oluştururken,  database'den vs. gibi bir veri kaynağından gelen verilerde Türkçe karakter sorunu yaşayabiliriz. Bu durumda bize

An error occurred while parsing EntityName

hatasını verir ve bizim de bu durumda yapmamız gereken encoding kısmını şu şekilde düzeltmek olmalıdır.

< ?xml version=\"1.0\" encoding=\"windows-1254\"? >

Bu işlemi yaptıktan sonra, ayrıca gerek duyulursa, '&' karakteri sorun çıkarması durumunda da, gelen veriyi replace ederek "&" yapmalıyız. Yani;

Replace("&", "& amp;")

yapmalıyız. Bu durumda herhangi bir hata almayacağız. 

12 Şubat 2011 Cumartesi

C#'da yield Kavrami

Daha onceki makalelerde Foreach iterasyonu hakkinda bilgi vermistim. Kisaca hatirlatacak olursak, IEnumerable interfacesini implement etmeyen bir class foreach iterasyonuna sahip olamiyordu. Bunun icin, o class'i IEnumerable interfacesinden implement edip, bu implementle birlikte override edilmesi gereken GetEnumerator metodunun icini doldurdugumuz zaman, artik bizim yazdigimiz sinifta da foreach ile gezebilecek duruma geliyorduk. Sunu da unutmayalim ki, GetEnumerator metodunu override ederken, MoveNext(), Reset() metotlarini ve Current isimli uyesinin iclerini doldurmamiz gerekiyordu.

Mantigi oldukca basit ama bazi projelerde, uygulamaya entegrasyonu sıkıntı çıkarabiliyor. Iste bu  sıkıntıları gidermek için C# 2.0 ile birlikte gelen yield keywordu sayesinde bu islemlerin tumu bizim icin arka planda yapilmis olacak.

Kullanimi oldukca basit;

Yine ayni sekilde, UrunYonetim sinifini olusturup, IEnumerable sinifindan kalitalim ve GetEnumerator sinifini override edelim.


namespace yieldKullanimi
{
    class UrunYonetim : IEnumerable
    {
        Urun[] _urunler;

        public UrunYonetim()
        {
            _urunler = VeriTabanindanOku();
        }

        private Urun[] VeriTabanindanOku()
        {
            Urun[] urunler = { new Urun(1, "Monitor", 200), new Urun(2, "Klavye", 80), new Urun(3, "Mouse", 40) };

            return urunler;
        }

        public IEnumerator GetEnumerator()
        {
            for (int i = 0; i < _urunler.Length; i++)
            {
                yield return _urunler[i].Ad;  
            }
        }
    }
}

Gordugunuz uzere, GetEnumerator sinifinda, onceden bir numarator sinifi olusturup(IEnumerator interfacesini implement eden sinif) nesnesini burada olusturup return ediyorduk. Daha sonra da MoveNext,Reset ve Current gibi uyelerin icini dolduruyorduk. Tum bunlari, GetEnumeratorun icine yazdigimiz kodlar yapiyor iste. for dongusuyle sayesinde, MoveNext metodunun ici yaziliyor. int i=0 diyerek Reset() metodunu cagiriyoruz, yield return_urunler[i].Ad diyerek de aslinda Current field'ini okuyoruz. Bunun sonucunda da, biz Urun sinifinin icinden string tipinden dolasip, urun isimlerini elde edebilecegiz.

Simdi de IL Disassambler(ILDASM) acarak, fiziksel olarak yazmadigimiz halde hangi metotlarin(uyelerin) olusturulduguna bakalim.


Gordugunuz uzere, biz MoveNext,Reset ve Current gibi uyeler yazmamamiza ragmen, yield keywordu sayesinde, arka planda bunlarin yazildigini goruyoruz. Programimiza buyuk olcude rahatlik getiren, is yukunu azaltan ayni zamanda da kod okulurlugu acisindan profesyonel yapisini koruyan yield'lar sayesinde hayat artik daha da guzel. :)

* Resme tıklarsanız, yeni ekranda, orjinal boyutunda erişebilirsiniz.