10 Mayıs 2019 Cuma

PDF Kopyalama Engeli (Disable Copy on PDF)

Selamlar,

Geliştirme yaptığım domain içerisinde bazı ekranlardan,
·        herhangi bir sunucuda halihazırda varolan PDF dokümanlarının download edilen,
·        yine bazı ekranlardan anlık üretilme yoluyla download edilen
PDF dosyalarında güvenliği bir tık daha artırmak amacıyla, kopyalama yapılamaması ihtiyacı hasıl oldu. Bir tık diyorum çünkü kopyalama işlemi engellense dahi piyasada envaiçeşit "convert pdf to word" gibi tool 'lar mevcut.

Peki madem pdf üzerinde kopyalama işlemini engellemek bu soruna çözüm değil, neden böyle bir ihtiyaç doğdu? Burada aslında pdf dokümanın amacını doğru anlamak gerekiyor:
PDF dokümanı son kullanıcı için tasarlanan, üzerinde değişiklik yapılmasının zaten istenilmediği bir uzantıdır. Bellibaşlı verilerin derlenip toparlanması veya analiz-raporlama gibi işlemlerin sonucu olarak kullanılması amaçlanan veyahut görüş bildirmek için kullanılan, mail vb. gibi yollarla son kullanıcıyla paylaşılan bir dosya türü denilebilir.

Koda geçmek gerekirse örnek olarak bir pdf download işlemi aşağıdaki gibi yapılıyor olsun:
 
var commonBo = new CommonBo();
string fileName = Request.QueryString["filenamePdf"];
string fileFolder = Server.MapPath("~/Templates/Temporaries/");
string htmlText = File.ReadAllText(fileFolder + fileName);
byte[] content = commonBo.HtmlToPdfConverter(htmlText);

HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Charset = "utf-8";
Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName + ".pdf");
HttpContext.Current.Response.OutputStream.Write(content, 0, content.Length);
HttpContext.Current.Response.End();
HttpContext.Current.Response.Close();

kullandığım örnekte pdf in beslendiği kaynak olarak html kullandım. Html den pdf e dönüştürme konusu apayrı bir konu fakat extra bilgi olması açısından "NReco", "TuesPechkin" gibi bazı 3th part dll ler kullanılabilir. Sonuç olarak stream e aktarabilecek bir byte array yeterli.



İndirilen pdf in kopyalanabildiği görülmekte, kopyalanamaması için download başlamadan önce program akışında araya girmek bir yöntem. Bu özelliği sağlayan Adobe 'un lisans gerektiren hatta bildiğim kadarıyla şu tarih-saat itibariyle indirme başına lisans isteyen sdk sı mevcut fakat ben örnekte "iTextSharp" olarak bilinen ücretsiz bir dll kullanacağım, şuan için son version:



using iTextSharp.text.pdf;
var commonBo = new CommonBo();
string fileName = Request.QueryString["filenamePdf"];
string fileFolder = Server.MapPath("~/Templates/Temporaries/");
var htmlText = File.ReadAllText(fileFolder + fileName);
byte[] content = commonBo.HtmlToPdfConverter(htmlText);

using (MemoryStream input = new MemoryStream(content))
{
    using (MemoryStream output = new MemoryStream())
    {
        PdfReader reader = new PdfReader(input);
        PdfEncryptor.Encrypt(reader, output, PdfWriter.DO_NOT_ENCRYPT_METADATA, null, "", PdfWriter.AllowPrinting);
        content = output.ToArray();
        Response.ContentType = "application/pdf";
        Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName + ".pdf");
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.BinaryWrite(content);
        Response.End();
    }
}

"iTextSharp" dll i içerisindeki "Encrypt" metodunu kullanara verilen "PdfWriter" options ları ile pdf üzerinde yapılmasına izin verilen özellikler "Allow" diyerek belirtilmeli. 




İndirilen pdf de kopyalamanın lock landığı görülmekte ve ctrl+c de clipboard a almıyor.



Permission Setting bölümünden de görüldüğü üzere "Printing" haricindeki "Content Copying" dahil  tüm yetkiler "Not Allowed" durumunda.


İllaki başka yöntemler de vardır, Bu yöntem işimi hızlı bir şekilde gördüğü için paylaşıyorum. Başka yöntemlerin bilgisine sahip olan arkadaşlar isterlerse yorum olarak paylaşabilirler.

Umarım faydalı olmuştur. Başka bir yazıda görüşmek dileğiyle, hoşçakalın ..

9 Eylül 2012 Pazar

C# 'da Döngüler - While, Do-While Döngüleri


            Merhaba arkadaşlar. Daha önceki yazılarımda da c shrap 'ta bu iki döngüyü ele almıştım. Bu yazımda da daha zengin bir anlatım ile while ve do-while döngülerini sizlere sunmaya çalıştım.

WHILE Döngüsü
While döngüsü de yine c sharp programlama dilinde sıkça kullanılan ve çok kullanışlı bir döngü tipidir. Parantezler içerisine for döngüsünün 2. bölümünde olduğu gibi bool tipine bir ifade (expression) isteyecektir. Bu bool ifede sağlandığı sürece döngünün dönmesi devam edecektir. Bu yüzden while kelimesinin türkçe anlamı “iken” olduğuna dikkat edersek; while döngüsü, döngü koşulu sağlandığı sürece dönmesi istenilen senaryolarda tercih edilir.

Kullanım şekli ise aşağıdaki gibidir.
         
     while (koşul)
            {
                //Koşul sağlandığı sürece çalışacak olan kod bloğu
            }

Bu bool tipindeki ifadenin, for döngüsündeki gibi tam olarak belirli bir bitiş noktası olmaması ile birlikte, yine for döngüsünün 3. bölümü (iteration)  gibi döngü değişkeni üzerinde bir öteleme ve yahut berilemeye ihtiyaç duyulmaz. Zaten hali hazırda while döngüsünde döngü değişkeni bulunmaz. Fakat istenirse bir değişken tanımlanıp ve while döngüsü içerisinde bu değişkenin değeri arttırılarak veya azaltılırak, for döngüsünün çalışma prensibi gibi çalıştırılabilir. Aşağıdaki örnekte bir while döngüsünün, for döngüsü gibi nasıl kullanılacağını görmekteyiz.

     int i = 0;
            while (i < 100)
            {
                i++;
                //Döngü içerisinde tekrar edilmesi istenen kodlar.
            }

Fakat tam ters mantık ile düşündüğümüzde for döngüsü, while döngüsü gibi kullanılamaz. Çünkü for döngüsünde bir bitiş noktası ve iteration part bulunmak zorundadır. Bu nokta da while döngüsünün diğer döngülere göre ayırt edici özelliğini ve güzelliğini görmekteyiz.
Aşağıdaki örnekte program, kullanıcıdan bir tuş basmasını istiyor ve basana kadar da  Console.ReadKey() kod satırı ile program akışını bu satırda bekletiyor. RaedKey metodu kullanıcıdan her hangibir tuşa basmasını bekler. Console.ReadLine () ise sadece enter tuşuna basılmasını bekler. Daha sonra CapsLock tuşu aktif mi yoksa değil mi kontrol ediyor. Bu kontrolü Console sınıfının geriye bool değer dönen CapsLock özelliği sayesinde yapıyor. While döngüsündeki koşulun başında ! (değil operatörü) olduğu için CapsLock tuşu False yani pasif olduğu sürece döngü dönmesine devam ediyor.
  
     while (!Console.CapsLock)
            {
                Console.Write("Lütfen bir tuşa basınız..");
                readline enter a basılmasını bekler
                Console.ReadKey(); 
                Console.WriteLine();
                Console.WriteLine("CapsLock: {0}", Console.CapsLock);
                Console.WriteLine();
            }

Ekran Çıktısı

           
C sharp ta başka kullanım alanlarını düşündüğümüzde, Sql Server ‘daki bir veritabanındaki bir tablodan tüm birden fazla kaydın (satırın) gelmesi istendiğinde: Ado.Net teknolojisinin bize sunmuş olduuğu System.Data.SqlClient kütüphanesinin altındaki sınıflardan bir tanesi olan SqlDataReader nesnesinin Read() metodunun kullanılması gerekir. Bu metod satırı okuyabildiği sürece alt satıra geçer ve aynı zamanda da yine okuyabildiği sürece geriye bool değer döndürür. Bu örnekte geliştiricinin, while döngüsünü kullanmasının gerekliliği, veri tabanına sorulan sorgu sonucunda kaç adet satır döneceği geliştirici tarafından kesin olarak kestirilememesidir. Bu yüzden aşağıdaki gibi bir while döngüsü kullanmak gerekir.

SqlConnection con = new SqlConnection("Server=.;Database=Northwind;UID=sa;PWD=1");
SqlCommand com = new SqlCommand("Select FirstName, LastName from Employees", con);
con.Open();
SqlDataReader dr = com.ExecuteReader();
while (dr.Read())
{
string isim = dr.GetString(0);
string soyisim = dr.GetString(1);
       listBox1.Items.Add(isim + " " + soyisim);
}
con.Close();

Böylece veri tabanından sorulan sorgu sonucunda kaç satır dönüyorsa, while döngüsündeki Raed metodu sayesinde hepsi karşılanabilir. Bu metod okuayabildiği satırı okur ve tek satırlık tablo tutar. Diğer while döngü adımında ise sorgu sonucuna göre sıradaki satırı hafızasında tutar. Bunu sağlayan da SqlDataReader nesnesidir. Uygulamadan veritabanına sorulan sorgu sonuçlarında, uygulama tarafına doğru bir veri akışı söz konusudur. SqlDataReader nesnesi, bu akışı karşılamada geliştiricilere yardımcı olan, boş bir bardak gibi düşünülebilir. Bu bardak sayesinde akan verileri kolayca kontrol edilebilir.

DO-WHILE Döngüsü
While dögüsünü döngümüz içerisindeki kod bloğunun kaç kere çalışacağını bilmediğimiz durumlar için kullanıyorduk. Eğer while 'daki koşul uymuyorsa program akışı döngüye girmeden devam ediyordu. Do-while döngüsünde ise bir programa "bir kere çalıştır, sonra koşul gerçekleştiği sürece tekrar tekrar çalıştır" diyoruz.  Aşağıdaki gibi do-while döngüsünün söz dizimine baktığımızda, aslında while döngüsünden tek farkının, koşuldan bağımsız olarak döngünün bir kere dönmesidir. Yani koşul sağlansa da sağlanmasa da döngü skopları içerisindeki kodlar bir defaya mahsus olmak üzere çalışacaktır.

            do
            {
                //Koşul sağlandığı sürece çalışacak olan kod bloğu
            } while (koşul);

Zaten program akışına göre, koşulun kontrol edildiği satır do skoplarının altındadır. Yani döngü skopları içerisindeki kodlar bir kere çalışır ve daha sonra while parantezleri içerisindeki bool ifade kontrol edilir. Bu bool ifadeden true sonucu döndüğü sürece döngü dönmesinde devam eder. False sonucu dönerse döngü içerisindeki kodlar hiç çalışmadan döngü skoplarından çıkar.
Bir örnek verecek olursak: klavyeden 0 değeri girilene dek girilen sayıların en büyük iki rakamı bize gösteren kod bloğunu do-while kullanarak yapalım.
           
     int birinci = 0, ikinci = 0, girilen = 0;
            Console.WriteLine("Lütfen sayı giriniz.");
            do
            {
                girilen = Convert.ToInt32(Console.ReadLine());
                if (girilen > birinci)
                {
                    ikinci = birinci;
                    birinci = girilen;
                }
                else if (girilen > ikinci)
                {
                    ikinci = girilen;
                }
            } while (girilen != 0);


Program kullanıcıdan sıfır değeri girilene kadar sayılar ister. Sıfır girilmediği sürece döngü içerisindeki kod bloğu çalışır ve döngü dönmeye devam eder. Girilen her sayıyı önceki iki sayı ile ayrı ayrı kıyaslar. Girilen sayı önceki iki sayıdan sayıdan büyükse değerlerini birbirlerine atar. Bunu yaparken de, minimum bir tane değişken kullanmalıdır. Bu algoritmaya "swap algorithm" (kaydırma algoritması) denir. Son olarak birinci ve ikinci değişkenlerinde en büyük iki sayı kalmış olacak.

Fakat c sharp programlama filinde do-while döngüsü her zaman tercih edilmez. Eğer do-while döngüsü kullanılacaksa çok iyi tasarlanmalı ve kullanıldığı algoritmada döngünün yeri çok iyi tespit edilmelidir. Aksi takdirde, geliştirici tarafından zor farkedilir mantık hatalarına yol açabilir.

            Umarım yardımcı olabilmişimdir. Başka bir yazıda görüşmek dileğiyle, hoşçakalın...

3 Eylül 2012 Pazartesi

C# 'da Döngüler - FOREACH Döngüsü

C sharp ‘da her hangi bir koleksiyon tipinin elemanlarını teker teker bir döngüde ele alabilir, istersek bu elemanlara değer atayabilir (set), istersek de bu elemanları okuyabiliriz (get). Bu işlemler için en ideal döngü Foreach döngüsüdür ki: kelime anlamı da her biri demektir. Biz de koleksiyon içerisindeki her bir eleman için dön tabirini kullanacağız. For döngüsünden farklı olarak her hangi bir iteration kullanmayız fakat arka planda kendisi bir sonraki elemana geçer. Bu yüzden foreach ile yapılabilen her şey for döngüsü ile de yapılabilir. Fakat for döngüsü ile yapılan her şey foreach döngüsü ile yapılır dersek yalan söylemiş oluruz.

Söz dizimine (syntax ‘ına) bakacak olursak, öncelikle koleksiyon içerisindeki her bir elemanın tipi yazılır. Daha sonra ilgili koleksiyonun her bir elemanına, foreach döngüsü içerisinde hangi isimle sesleneceğimiz belirten bir değişken adı belirtilir. Daha sonra “in” anahtar sözcüğü kullanılarak hangi koleksiyonun elemanlarında dönecek isek o koleksiyonun adı yazılır. Aşağıda bir örnek bulunmaktadır.
     
     foreach (elemanTipi değiskenAdı in koleksiyonAdi)
            {   
            }

Foreach Döngüsü ile koleksiyon içerisindeki her bir elemanın değerini okuma :

Hemen bir örnek üzerinde foreach döngüsü ile bir koleksiyon içerisindeki elemanları okumayı inceleyelim. “Sehirler” adında string bir dizimiz olsun ve bu dizi elemanlarını bir kontrolde teker teker gösterelim. Bir “Windows Form Application” açalım. Formumuza bir adet ListBox kontrolü bırakalım. ListBox ‘ın ismini de “lstOgreler” olarak değiştirelim. Kodlarımızı formun Load event ‘ine yazalım.

     string[] sehirler = { "Adana", "Adıyaman", "Afyon", "Ağrı", "Amasya", "Ankara", "Antalya" };

            foreach (string il in sehirler)
            {   
                lstOgeler.Items.Add(il);
            }

Ekran Çıktısı

Yukarıdaki örnekte sehirler dizisindeki her bir eleman için dön ve her bir elemanı ListBox ‘ın item ‘larına (elemanlarına) ekle demiş olduk. Koleksiyonun her bir elemanı string olduğu için tipini en başta belirmiş olduk.

Yukarıdaki "il" adlı string değişkene "foreach iterator" denir. Bu yapı döngü nesnesi yardımıyla her bir elemanı tek tek ele alabilmemizi sağlar. Ancak bu elemana herhangi bir şekilde değer ataması yapmanız mümkün değildir.

Foreach Döngüsü ile koleksiyon içerisindeki her bir elemana değer atma :

Foreach döngüsünde sadece ileriye doğru bir iteration (Forward Only) söz konusudur. Ayrıca içerisindeki iteratioin variable (öteleme değişkeni) Read Only yani sadece okunabilirdir. Bu nedenle değer atarken bu değişkene değil, bu değişkenin temsil ettiği elemana değer atanmalıdır.

Öncelikle hatalı kullanıma bir örnek verelim. Yine “Sehirler” adında, boyutu 7 olan bir string dizi tanımlayalım.
string[] sehirler = new string[7];

Bu dizinin tüm elemanlarına “adana” değerini atamaya çalışalım.

            foreach (string il in sehirler)
            {
                il = "Ankara";
            }

Yukarıda da bahsettiğimiz gibi derleme zamanındaki (Compile Time) hata mesajında da görüldüğü gibi (Cannot assign to 'il' because it is a 'foreach iteration variable) ”iteration değişkenine değer atanamaz.” hatasını almaktayız. Bunun yerine örneğimizde  koleksiyon olarak dizi kullandığımız için o dizinin elemanlarına değer atamalıyız. Bunun için kaynakDizi adında kaynak bir dizi tanımlayalım. Bu dizinin elemanlarını da hedefDizi adındaki hedef dizimizin elemanlarına atalım. İndex bilgisi için de index adında integer tipli bir değişken tanımlayalım ve her döngü adımında bu index değişkenin değerini, ilgili dizinin sıradaki elemanına geçmesi için bir arttıralım.

           string[] kaynakDizi = { "Adana", "Adıyaman", "Afyon", "Ağrı", "Amasya", "Ankara", "Antalya" };
            string[] hedefDizi = new string[7];
            int index = 0;
            foreach (string il in sehirler)
            {
                //il = "Ankara";
                hedefDizi[index] = kaynakDizi[index];
                lstOgeler.Items.Add(hedefDizi[index]);
                index++;
            }

Fakat bu örnek için for döngüsü daha idealdir. Foreach döngüsü genellikle tanımladığımız sınıf  (class) tiplerini koleksiyon şeklinde tutabilen tiplerin elemanlarında dönmek için kullanılır. Örneğin “urun” adında bir class tanımlayalım ve ad, stok, fiyat gibi bir takım özelliklere sahip olsun. Ve herhangi bir ürün nesnesi “get” edilmek (okunmak) istendiğinde “full-qualification name” (namespace.class) ismi çıkmaması için object sınıfındaki ToString() metodunu farklı davrandıralım yani aşağıdaki gibi “override” edelim.

    public class urun
    {
        public string ad { get; set; }
        public int stok { get; set; }
        public decimal fiyat { get; set; }

        public override string ToString()
        {
            return this.ad;
        }
    }

Her bir elemanı bu sınıf tipinde olan bir koleksiyon tanımlamak için “List<>” generic sınıfından faydalanabiliriz. Bu sınıfın “Add” metedu sayesinde koleksiyona kolay bir şekilde eleman ekleyebiliriz, tabi ki şart tipi ürün olması gerekiyor.

     List<urun> urunler = new List<urun>(); 

           
            urunler.Add(new urun { ad = "Domates", fiyat = 2.5m, stok = 100 });
            urunler.Add(new urun { ad = "Biber", fiyat = 1.5m, stok = 250 });
            urunler.Add(new urun { ad = "Patlıcan", fiyat = 2.0m, stok = 50 });

Artık elimizdeki bu koleksiyonun elemanlarında foreach kullanarak dönebiliriz, değerlerini okuyaabilir herhangi bir kontrole yazdırabiliriz.

     foreach(urun u in urunler)
            {
                listBox1.Items.Add(u);
            }

“urunler” koleksiyonun içerisindeki her bir elemanın tipi “urun” olduğundan dolayı tip belirtildi. Artık bu elemanlara foreach içerisinde “u” adıyla seslenilecektir. Herhangi bir ListBox kontolüne eklediğimizde urun sınıfındaki “ToString” metodu çalışarak ürünün adı görünecektir.


Buradaki asıl dikkat edilmesi gereken nokta foreach döngüsüni kullanarak herhangi bir koleksiyonda dönebilmek için o koleksiyonun .Net ortamında “IEnumerable” interface ‘ini implamente almış olması gerekir. Çünkü bu interface içinde “GetEnumarator” adında bir metod bulunur ki bu metod da IEnumerator interface ‘ini implemante almıştır. IEnmarator interface ‘i içerisinde ilgili sınıf nesnesinin foreach döngüsünde döenebilmesini sağlayan 3 adet metod bulunur: Current, MoveNext, Reset olmak üzere. Current foreach içerisinde o anki elemanı teslim eder, MoveNext sıradaki elemana geçmek için koleksiyonun index ‘ini 1 arttırır. Sırada eleman varsa true sonucu döner ve o eleman get edilmek istendiğinde yine Current metodu çalışacaktır. Sırada eleman yoksa da false dönecektir ve index değerini -1 yapan yani döngüden çıkılmasını sağlayan Reset metodunu çağıracaktır. Custom yani geliştirici tanımlı normal ya da generic koleksiyon tanımlamasını ilerleyen yazılarımda anlatacağım. Örneğin List tipine sağ tıklayıp “go to defination” seçeneğini seçtiğimizde “IEnumarable” interface ‘ini implemante almış olduğunu görüyoruz.




Ya da c sharp ‘ta “ComboBox.ObjectCollection” ve ya “ListBox.ObjectCollection” gibi IEnumerable interface ‘ini implamente almış (uygulamış) olan özel koleksiyon tiplerinin elemanlarında dönebilmek için de kullanılabilir. Hemen bir örnek üzerinde görelim:
    
     foreach (urun u in listBox1.Items)
            {
                if (u.ad == "Domates")
                {
                    MessageBox.Show("5 kilo al!");
                }
            }

ListBox ‘ın item ‘larının da .Net ‘deki tanımlamasına gittiğimizde IEnumerable interface ‘ini implamente almış olduğunu görürüz.




Diğer bir örnek, formunuzdaki tüm TextBox ‘ların Text özelliklerini temizlemek isteyebilirsiniz. Bunun için teker teker TextBox ‘ların textini temizleyeceğinize aşağıdaki gibi foreach döngüsünü kullanarak, formun kontrollerinde gezip, eğer bu kontrol TextBox ise textini temizle diyebilirsiniz. Tabi ki bir tip kontrolü yapılırken “is” anahtar kelimesiyle yapılmalıdır. Ayrıca "Controls" koleksiyonu bize formun üzerindeki tüm kontrolleri Control tipinde teslim edecektir. Fakat dikkat edilmesi gereken nokta TextBox ‘ın Text özelliğine erişebilmek için elde ettiğimiz kontrolü TextBox ‘a “cast” etmeliyiz ki; o kontrol TextBox gibi davranabilsin. Böyle TextBox nesnesinin “Clear” metodu sayesinde TextBox ‘in texti temizlenebilir.

     foreach (Control ctrl in this.Controls)
            {
                if (ctrl is TextBox)
                {
                    (ctrl as TextBox).Clear();
                }
            }

This” anahtar sözcüğü kullanıldığı sınıfın nesnesini temsil eder. (Bu yüzden static sınıflarda “this” sözcüğü kullanılmaz.) Bu örnekte “this” sözcüğünü, Form1 sınıfı içerisinde kullandığımız için, bu sınıfın bir öğesi gibi davranacaktır. “Controls” koleksiyonunun .Net ortamındaki tanımına gittiğimizde yine IEnumerable interface ‘ini implamente almış olduğunu görürüz.


IEnumerable ve IEnumarator interface kullanımı daha sonraki makalelerimde ayrıntılı bir şekilde ele alacağım. Başka bir yazıda görüşmek dileğiyle, hoşçakalın... 

C#' da Döngüler Giriş - FOR Döngüsü


C #’DA DÖNGÜLER
Programlamada bir uygulama geliştirilirken kullanılan algoritma gereği, bazı kod bloklarının, defalarca tekrar tekrar çalışması gerekebilir. Her defasında bu kod bloklarının yazılması bir şeylerin ters gittiğinin habercisi demektir. Bu nedenle programlama dillerinde “döngüler” kullanılır. Döngüler sayesinde, her defasında istenilen değerlere göre, istenilen sayıda tekrar etmesi istenilen kod blokları, zahmetsiz ve kod tekrarı yapılmadan çalıştırılabilir.  Döngüsüz bir programlama dili düşünülemez. Kullanılmaz ise uygulamanın algoritması gereği gereksiz yere kod tekrarı yapılacaktır ki, kodlarınızın ne kadar tekrar etmesi gerektiğine göre ciddi bir koddan söz edilebilir, bu durum da hiçbir yazılım geliştirici için kabul edilebilir değildir.

            Bu yazımda c sharp programlama dilindeki döngüler ele alınacaktır. C sharp ‘da kullanılan başlıca döngüler :
  1.  FOR (için) Döngüsü
  2. FOREACH (her biri için) Döngüsü
  3. WHILE (iken) Döngüsü
  4. DO-WHILE (yap-iken) Döngüsü

FOR Döngüsü

For döngüsünü diğer döngülerden ayıran en büyük özellik döngünün kaç kere döneceği bellidir ya da önceden kestirilebilir. Günlük hayattan örnek vermek gerekirse Formula araba yarışları güzel bir örnek olacaktır. Çünkü yarışın bitme koşulu vardır. Örneğin arabalar 70 turu tamamladıktan sonra diye bir koşul mevcuttur. Yani yarışın ne zaman biteceği bellidir.

For döngüsünün çalışma prensibini hemen bir örnek üzerinde inceleyelim. Örneğin tasarlanan bir kullanıcı formunda, kullanıcıdan doğum tarihi bilgisi isteniliyor. Fakat programcının belirlediği yıl, ay ve gün aralığından, kullanıcının bu bilgisini seçmesini bekleniyor. Yıl aralığının 1900-2012, ay aralığının 0-12, gün aralığının 0-(28-29-30-31) olarak belirlendiğini düşünelim.

Visiual Studio 2010” üzerinden bir “Windows Form Application”  açalım. Kullanıcı arayüzünü aşağıdaki gibi tasarlayalım.

Form kontrolüne, Toolbox penceresinde standart kontroller sekmesi altından 3 adet ComboBox kontrol eklendi. ComboBox ‘lara TextBox gibi değer girilmesini önlemek amacıyla DropDownStyle özelliğini DropDownList yapıldı. Name özellikleri sırasıyla; cmbYil, cmbAy, cmbGun olarak değiştirildi.

Yine Toolbox ‘dan 3 adet de Label kontrolü atıldı. Text özelliklerine görüldüğü gibi değerleri girildi. Name özelliklerine de sırasıyla; lblYil, lblAy, lblGun değerleri verildi.

Bu işlemi for döngüsü ile yapalım. Form ekrana geldiğinde ComboBox ‘lar dolu olarak gelmesini istiyorsak Form ‘un Load event ‘ini Handle edelim.

 private void frmForDongusu_Load(object sender, EventArgs e)
        {
            for (int x = 1900; x <= DateTime.Now.Year; x++)
            {
                cmbYil.Items.Add(x);
            }
        }

For döngüsü üç bölümden oluşmaktadır. Bölümler noktalı virgüllerle ayrılır. Birinci bölüm declaration (tanımlama) ve setting (değer atama) bölümüdür. Burada değişken tanımlanır ve o değişkene bir başlangıç değeri atılır. Bu bölüm döngü ne kadar dönerse dönsün bir defa çalışacaktır ve döngünün ilk başladığı bölümdür. Fakat istenirse tanımlama aşağıda örnekteki gibi bu bölümden önce yani for döngüsünden önce yapılabilir.

     int x=0;
     for (x = 1900; x <= DateTime.Now.Year; x++)
            {
                cmbYil.Items.Add(x);
            }

            For döngüsü içerisinde kullanılan değişkene for döngüsü değişkeni (for loop variable) denir ve herhangi istenilen bir isim verilebilir.

İkinci bölüm döngünün bitiş noktasını belirtir. Burada bir koşul yani geri dönüş tipi bool olan bir criterian (kriter) belirtmeliyiz. Bu kriter for döngümüzün bitiş kriteridir. Yani for değişkeni bu kriterden geçtiği sürece yani bu koşuldan “true” sonucu döndüğü sürece, for döngüsü çalışmasına devam edecektir. Burada verdiğimiz değer değişkenimizin for döngüsünden çıkmadan önce alacağı son değerdir ve bu değişkenin ömrü sadece for skoplarında geçerlidir.

Üçüncü bölüm “iteration” (öteleme-berileme) bölümüdür. Ötelemeden kasıt döngü değişkeninin değerinin istenilen miktar kadar arttırılması, berilemeden kasıt ise döngü değişkeninin değerinin istenilen miktar kadar azaltılmasıdır. Değişkenin bir dahaki for düngü adımında ne kadar arttırılacağını ya da ne kadar azaltılacağını belirler. Örneğin ikişer ikişer arttırmak istersek; aşağıda da görüldüğü gibi, bu bölüme x+=2 ya da x=x+2 şeklinde yazmamız yeterli olacaktır.

     for (int x = 1900; x <= DateTime.Now.Year; x+=2)
            {
                cmbYil.Items.Add(x);
            }

Iteration bölümünde döngü değişkenin değerinin arttırılması şart değildir. Uygulamanızdaki senaryoya göre bu değişkeni azaltmanızda gerekebilir. Örneğin aşağıdaki gibi ComboBox ‘a yılları tersten sıralamamız daha mantıklı olacaktır.

     for (int x = DateTime.Now.Year; x >=1900; x--)
            {
                cmbYil.Items.Add(x);
            }

Örneğimiz geri kalan kısmına devam etmek gerekirse, ayları da cmbAd adlı ComboBox ‘a sıralamalıyız. Bunun için aylar adında string bir dizi tanımlayalım ve dizilerin indexer yapısı sayesinde bu dizinin elemanlarını teker teker okuyalım.

 private void frmForDongusu_Load(object sender, EventArgs e)
        {           
     for (int x = DateTime.Now.Year; x >=1900; x--)
            {
                cmbYil.Items.Add(x);
            }

            string[] aylar = { "Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık" };
            for (int index = 0; index < aylar.Length; index++)
            {
                cmbAy.Items.Add(aylar[index]);
            }
        }

Görüldüğü üzere iki tane for döngüsü ile 2iki ComboBox kontrolünü verilerle doldurdu. For döngüsüne “breakpoint” atarak, uygulamamızı debug modda çalıştırdığımızda, program akışı öncelikle declaration-setting bölümüne (1.bölüm), daha sonra koşul bölümüne (2.Bölüm) ve daha sonra ise iteration bölümüne uğramadan for döngüsünün içerisindeki kodlardan devam edecektir. Yani döngü değişkeninin ilk değeri için döngü içerisindeki kodlar bir defaya mahsus olmak üzere çalışacaktır. Bu kodlar çalıştıktan sonra, program akışı iteration bölümüne uğrar. Burada döngü değişkeni yeni değerini aldıktan sonra tekrardan değişkenin yeni değerine göre ikinci bölümdeki koşul kontrol edilir. Koşuldan true sonucu dönerse döngü dönmeye devam edecektir. False dönerse de döngü içerisindeki kodlar çalışmadan döngüden çıkılır.

Ay bilgisi seçilmeden gün bilgisinin seçilmesini istemiyorsak yine Formun Load event ‘inde “cmbGun” ve “lblGun” kontrollerinin “Enable” özelliklerine “false” değerini verelim.

cmbGun.Enabled = lblGun.Enabled = false;

Ay bilgisi girildikten sonra lblGun ve cmbGun kontrollerinin aktif olmasını istiyorsak bu kontrolü cmbAy kontrolünün SelectedIndexChange eventinde yapmamız gerekiyor.

 private void cmbAy_SelectedIndexChanged(object sender, EventArgs e)
        {
            GunDoldur();
        }

 private void GunDoldur()
        {
            if (cmbAy.SelectedIndex == -1) return;
            if (cmbYil.SelectedIndex == -1) return;
            cmbGun.Items.Clear();
            cmbGun.Enabled = lblGun.Enabled = true;

            switch (cmbAy.SelectedItem.ToString())
            {
                case "Şubat":
                    if (DateTime.IsLeapYear((int)cmbYil.SelectedItem))
                    {
                        for (int i = 1; i <= 29; i++)
                        {
                            cmbGun.Items.Add(i);
                        }
                    }
                    else
                    {
                        for (int i = 1; i <= 28; i++)
                        {
                            cmbGun.Items.Add(i);
                        }
                    }
                    break;
                case "Ocak":
                case "Mart":
                case "Mayıs":
                case "Temmuz":
                case "Ağustos":
                case "Ekim":
                case "Aralık":
                    for (int i = 1; i <= 31; i++)
                    {
                        cmbGun.Items.Add(i);
                    }
                    break;
                case "Nisan":
                case "Haziran":
                case "Eylül":
                case "Kasım":
                    for (int i = 1; i <= 30; i++)
                    {
                        cmbGun.Items.Add(i);
                    }
                    break;

                default:
                    break;
            }
        }

Bu kontrolü de switch karar yapısıyla gerçekledik. Bilindiği üzere bazı aylar 31, bazı aylar  30, Şubat ayı ise 4 ile bölünebilen yıllarda (artık yıl denir) 29, değer yıllarda 28 çeker. 29 çeken yılları DateTime sınıfı altındaki, geriye bool tipinde değer dönen isLeapYear metodu ile bulabiliriz. Eğer bu metoda verilen parametre artık yıl ise metottan geriye “true” sonucu dönecektir. “True” dönmesi halinde for döngüsünün bitiş kriterini: 29 ‘dan küçük yada 29 ‘a eşit olduğu sürece dön diye belirtebilirim.

Bu kontrollerin, cmbYil adlı ComboBox ‘ın değerinin değişmesi ile de yapılmasını istiyorsak; aşağıdaki gibi cmbYil kontrolünün SelectedIndexChanged event ‘inde de GunDoldur metodunu çağırmamız gerekmektedir.

 private void cmbYil_SelectedIndexChanged(object sender, EventArgs e)
        {
            GunDoldur();
        }

Aşağıdaki diğer bir örnekte alfabe yazdırıldı. Fakat burada dikkat edilmesi gereken nokta: for döngüsü içerisinde char tipindeki herhangi bir değişkeni for döngüsünün iteration bölümünde kullanırken o char ‘ın ascii değerlerine göre bir iteleme yada öteleme yapacağı unutulmamalıdır. Yani iteration ‘da char ‘dan int tipine “implicit converting” (kapalı tip dönüşümü) yapar. Bu yüzden ekrana yazarken bu ascii değerlerini (int tipinde) tekrar char tipine dönüştürmek gerekir. Bu da “explicit converting” (açıktan tip dönüşümü) yapılması gerek demektir.

     for (int i = 'A'; i <= 'Z'; i++)
            {
                cmbYil.Items.Add(Convert.ToChar(i));
            }

Sonsuz Döngü Mantığı

For düngüsünün mantığı iyi kurgulanmalıdır. Bir mantık hatası for düngüsünü sonsuz bir döngüye sokabilir ve bu istenmeyen bir durumdur. Aşağıdaki örnekte for içindeki değişken 2013 ‘den başlamış ve 2012 ‘den büyük olana dek dönmeye devam et demiş bulunuyoruz. Bu deyim de sonsuza dek dön demek oluyor. Bu işlemi formun Load event ‘inde yaptığımız için program akışı bu for döngüsünde takılıp kalacak ve formum ekrana hiç gelmeyecektir.


Başka bir yazıda görüşmek dileğiyle, hoşçakalın...