Event'lar yani olaylar önceden belirlenmiş şartlar oluştuğunda sistem tarafından otomatik olarak çalıştırılan fonksiyonlardır. Bu fonksiyonların çalışmalarını düzenleyebilmek için bir Property(Özellik) ile koordineli olarak çalışmaları gereklidir. Önceki yazılarımızda C# dilinde nasıl bileşen oluşturacağımızdan bahsetmiştik. Hatta örnek bileşenimizi oluştururken kendi belirlediğimiz özellikler eklemiş ve bunların naısl çalıştığını görmüştük. Şimdi ise yine bizim oluşturduğumuz bileşenlere nasıl kullanıcı tanımlı olaylar eklenebileceğini inceleyeceğiz. Bir bileşene olay tanımlayabilmek için temsilcilerden faydalanmak durumundayız. Önceki yazımızda bundan bahsetmiştik temsilci ile ilgili bilgilerinizi tekrar gözden geçirmek isterseniz http://olcayguzel.blogspot.com/2011/04/c-delegate.html adresindeki makaleye gözatabilirsiniz. Şimdi gelelim nasıl olay oluşturacağımıza.
Şimdi oluşturacağımız olay şu işi yapacak: Hatırlarsanız önceki makalemizde yapılan bir işlemin devam ettiğini kullanıcılara bildireceğimiz bir bileşen hazırlamıştık. Varsayılan olarak üzerinde "İşleminiz devam ediyor. Lütfen bekleyiniz" yazıyordu ancak programcı isterse bu yazıyı değiştirebiliyordu. Bileşenin olaylarını incelediğinizde başlık değiştiğinde çalışacak bir olay olmadığını farketmişsinizdir. Çünkü herhangi bir olay tanımlamamıştık. Şimdi bu eksikliği kapatacağız ve "BaslikDegistiginde" adıyla bir olay oluşturacağız.
Daha önce de söylediğimiz gibi olayları etkin bir şekilde kullanabilmek için tanımlayacağımız özelliklerle birlikte kullanmalı. Kullanılan özellik değiştiğinde tanımlayacağımız olayın tetiklenmesini sağlamalıyız. Öncelikle olay tanımlarken hangi adımlardan geçeceğiz ondan bahsedelim.
1- Tanımlanacak olay ile koordineli çalışacak özellik tanımlanması
2- Tanımlanan özellik için get{} ve set{} bloklarının oluşturulması
3- Tanımlanacak olay tetiklendiğinde çalışacak fonksiyon için bir temsilci tanımlanması.
4- Temsilci ile birlikte çalışacak olay tanımlanması
5- Olay tetiklendiğinde çalışacak fonksiyonun tanımlanması
6- Fonksiyon ile tanımlanan olay arasında bağ kurulması
Şimdi adım adım işlemlerimize başlayalım.
1.Adım : Bildiğiniz gibi bir özellik tanımlanırken öncelikle özellik tarafından class içinde kullanılacak bir değişken tanımlanır. Bu değişken genellikle private olarak tanımlanır. Fakat dilerseniz diğer erişim belirleyicilerini de kullanabilirsiniz. Burada başlık bilgisinin değiştiği zaman tanımlayacağımız olayın çalışmasını istediğimiz için var olan "baslik" değişkenini ve "Baslik" özelliğini kullanabiliriz. baslik değiskeni şu şekilde tanımlanmıştı.
private string baslik = "İşleminiz devam ediyor. \r\nLütfen Bekleyiniz";2.Adım : Bu adımda class dışından erişim için özellik tanımlaması yapıyoruz. Yine var olan Baslik özelliği işimizi görecektir. Baslik özelliği şu şekilde tanımlanmıştı.
public string Baslik
{
get { return baslik; }
set {
if (value.Trim() != "")
{
baslik = value;
}
Ayarlar();
}
}
3.Adım : Bu adımda olayımız için bir temsilci tanımlıyoruz. Bu tanımlama sırasında olayın içermesini istediğimiz parametre tanımlamasını da yapıyoruz.
public delegate void customevent();
Şu durumda parametreye ihtiyacımız yok ama dilerseniz adettendir deyip parametre ekleyebilirsiniz. temsilcimizin public olarak tanımlandığına dikkat edin. Eğer "internal" olarak tanımlasaydık programcılar olayı kullanamayacaktı bu durumda işe yaramayan bir olay tanımlamış olacaktık.
4.Adım : Sıra geldi olay tanımlamasının yapılmasına. Bu tanımlama sırasında dikkat etmemiz gereken iki nokta var. Birincisi temsilci ile olay tanımlaması yapılırken temsilcinin erişim düzeyi olayın erişim düzeyini kapsıyor olması gereklidir. Yani ya ikisi de aynı erişim düzeyinde(public veya internal). veya temsilci daha üst düzeyde olması gerekiyor. Olayı internal olarak tanımlarsak farklı namespace içinden olaya erişim olmayacağı için amacımızın dışına çıkmış olacağız o yüzden her ikisini de public olarak tanımlıyoruz. Dikkat etmemiz gereken ikinci nokta ise olayımıza vereceğimiz için kullanıcıların göreceği isimdir. Seçtiğimiz ismin anlaşılır olmasına özen göstermeliyiz.
public event customevent BaslikDegistiginde;5.Adım : Bu adımda tanımladığımız olay tetiklendiğinde çalışacak fonksiyonu tanımlıyoruz. Kullanıcıların olayın tetiklenmesi gerekmediği durumlarda fonksiyonun adını kullanarak çağırmalarını istemiyoruz. Programlar açıcından sonucu belli olmayan şeyler oluşabilir. O yüzden fonksiyonumuzu private olarak tanımlıyoruz. Fonksiyonumuz şöyle bişey olacak
private void BaslikDegisim()
{
if (Baslik == "Olcay") MessageBox.Show("Hoşgeldin Olcay, sen başlığı istediğin gibi değiştirebilirsin");
}6.Adım : Şimdi herşeyi tanımladığımıza göre parçaları birleştirme zamanı geldi. Öncelike fonksiyonumuzla olayımız arasında bağ kuruyoruz. Bunu Yapıcı (Contructor) metot içinde yapıyoruz ki bileşen ilk oluşturulduğu andan itibaren çalışsın.
public Progress()
{
InitializeComponent();
BaslikDegistiginde += new customevent(BaslikDegisim);
Ayarlar();
} Son olarak özellik ile fonksiyonumuz arasında bir bağ kuruyoruz. Bunu da Baslik özelliğinin set{} bloğu içinde yapıyoruz. bu sayede Baslik özelliğine yapılan her atama işlemi sonucundan tanımladığımız olay tetiklenecektir. Tanımladığımız Baslik özelliğinin son hali şu şekilde
public string Baslik
{
get { return baslik; }
set
{
if (value.Trim() != "")
{ baslik = value; }
Ayarlar();
BaslikDegistiginde.Invoke();
}
} Kodlarımızı derliyoruz ve gördüğünüz gibi sorunsuz çalışıyor. Olayın tetiklenmesini görmeniz açısından MessageBox kullandım ama siz kodları kendi istediğiniz gibi değiştirebilirsiniz.
Tüm bunlara ek olarak aynı özelliklerde olduğu gibi olaylara da açıklama satırı eklenebilir. Olayımızı tanımladığımız satırda
[Description("Baslik metni değiştiğinde tetiklenir")]
public event customevent BaslikDegistiginde;
şeklinde bir düzenlemeyle tasarım alanında olayımız için bir açıklama belirtebiliriz.
18 Nisan 2011 Pazartesi
C# Delegate
C# dilinde delegate kavramı C ve C++ dillerindeki fonksiyon işaretçilerine karşılık gelir. Yani delegate türünde bir değişken kendisine atanan bir fonksiyonun adresine sahiptir. delegate türü değişkenlerin C ve C++ dilindeki fonksiyon işaretçilerinden farkı Nesne Yönelimli Programlama Tekniğine uygun bir şekilde tasarlanmış olmaları, ve güvenli bir şekilde kullanılabilmeleridir. Burada güvenlik kullanımdan kastedilen, delagate türü değişkenlerin RAM üzerinde sadece yetkili oldukları yani kendilerini çalıştıran programın yer aldığı bellek bölgesine erişim hakları olduğudur.
Bir delegate birden fazla fonksiyona işaret edebilir. Böyle bir durumda delegate çağrıldığında işaret ettiği bütün fonksiyonlar atanma sırası ile çalıştırılacaktır. Bir fonksiyonun delegate aracılığıyla çağırılabilmesi için delegate tanımlanırken belirtilen bütün özelliklere sahip olmalıdır. Aksi takdirde derleme anında hata meydana gelir. İsterseniz önce bir delegate nasıl tanımlanır onu görelim daha sonra küçük bir uygulamayla çalışma anında nasıl davrandığını inceleyelim.
Delegate türü değişkenler Class içerisinde tanımlanabileceği gibi class dışında da tanımlanabilir. işaret edeceği fonksiyon ise yine herhangi bir yerde tanımlanmış olabilir. Bu durumda yani delegate ve onun işaret edeceği fonksiyon farklı class tanımlamaları hatta farklı namespace içindeyse o fonksiyona erişimin olması gereklidir. Yani public bir fonksiyon olmalıdır. Fakat fonksiyon aynı class içinde tanımlanmışsa böyle bir zorunluluk yoktur.
Delegate tanımlamasının herhangi bir yerde yapılabileceğinden bahsetmiştik. Aşağıdaki gibi bir kullanım geçerlidir ve hem derleme anında hem de çalışma anında hata vermez.
using System;
delegate void delegatedeneme (string metin, double d, double p);
namespace DelegateKullanimi
{
class DelegateKullan
{
static void Main(string[] args)
{
}
}
}
Yukarıdaki tanımlamadan parametre olarak 2 tane double türünden değer alan, geriye double türünden bir değer döndüren fonksiyonları temsil etmek üzere bir temsilci tanımladığımızı anlıyoruz. Burada delegate tanımlanırken erişim belirleyicisi kullanılmadığı dikkatinizi çekmiştir. Delegate türü değişlenler sadece "internal" veya "public" olarak tanımlanabilir. Varsayılan türü internal dir. Yani burda olduğu gibi erişim belirleyici belirtilmezse varsayılan değer yazılmış kabul edilir. internal erişim belirleyicisi delegate değişkenine aynı namespace içerisinden erişimi imkanı verir.
Şimdi işi biraz daha ilerletelim. İki tane fonksiyonumuz olsun. Bunlardan biri parametre olarak bir string ve iki tane integer türü değişken alsın ve bu iki sayıyı çarpsın diğeri de yine parametre olarak bir string ve iki integer değişken alsın fakat üs alma işlemi yapsın. Kodlamaya geçelim
static void UsAl(string metin, double d, double p)
{
Console.WriteLine(metin + " " + Math.Pow(d,p));
}
static void Carp(string metin, double d, double p)
{
Console.WriteLine(metin + " " + d * p);
}
Bu fonksiyonları test edelim çalışıp çalışmadıklarını görelim.
static void Main(string[] args)
{
UsAl("Fonksiyon : ",6, 4);
Carp("Fonksiyon : ",6, 4);
Console.ReadLine();
} Kodlarımızı derliyoruz ve gördüğünüz gibi çalışıyor. Zaten çalışmamasını beklemiyorduk. Şimdi gelelim delegate değişkenimize bu fonksiyonları tanıtmaya. Yine "Main(string[] args)" fonksiyonu içinde delegate değişkenimizin türünden bir nesne oluşturuyoruz(delegate türü değişkenlerin Nesne yönelimli programlama tekniğine uygun tasarlandıklarından bahsetmiştik.). Fonksiyonumuz şu hale geldi.
static void Main(string[] args)
{
delegatedeneme temsilci = new delegatedeneme(UsAl);
UsAl("Fonksiyon : ",6, 4);
Carp("Fonksiyon : ",6, 4);
Console.ReadLine();
} Artık temsilci nesnemiz "UsAl(string metin, double d, double p)" fonksiyonunu temsil ediyor. Hatırlarsanız delegate türü değişkenlerin birden fazla fonksiyona işaret edebildiklerinden bahsetmiştik. Bbunu sağlamak için operatorlerden faydalanabiliriz. Delegate değişkenine temsil etmesi için fonksiyon eklemek istediğimizde
temsilci += Carp;
çıkarmak istediğimizde ise
temsilci -= Carp;
komutlarını kullanabiliriz. Şimdi temsilcimize "Carp(string metin, double d, double p)" fonksiyonunu da ekleyelim.
temsilci += Carp; komutunu temsilci tanımlama satırından sonraki satıra ekliyoruz.
Herşey güzel fonksiyonları oluşturduk, temsilcimizi oluşturduk, fonksiyonları temsilcimize tanıttık.. Peki bunları nasıl çalıştıracağız. Bunun iki şekilde yapabiliriz.
1.Yol : Delegate nesnesinin "Invoke()" fonksiyonunu kullanırız.Parametreler bu kısımda girilir.
Örneğin;
temsilci.Invoke("Temsilci : ", 6, 4);
2.Yol : Doğrudan temsilciye parametre vererek temsil edilen fonksiyonları çalıştırabiliriz.
Örneğin;
temsilci("Temsilci : ", 6, 4); Ben ikinci yöntemi kullanmak istiyorum. Main(string[] args) fonksiyonumuzun en son hali şöyle
static void Main(string[] args)
{
delegatedeneme temsilci = new delegatedeneme(UsAl);
UsAl("Fonksiyon : ", 6, 4);
Carp("Fonksiyon : ", 6, 4);
temsilci += Carp;
temsilci("Temsilci : ", 6, 4);
Console.ReadLine();
}Kodlarımızı derleyip çalıştırdığımızda şöyle bir çıktı elde ediyoruz.
Şu an hayal kırıklığı yaşıyor olabilirsiniz ama biraz daha sabrederseniz delegate kullanmanın nasıl bir avantaj olduğunu göreceksiniz. Şuan sadece kod karmaşasını ortadan kaldırmaya yardımcı olduğunu gördük. Peki performans nasıl acaba? Dilerseniz hemen bunu da test edelim. Bunun için class seviyesinde "DateTime" türünde bir değişken oluşturuyoruz.
static DateTime tarih; UsAl ve Carp fonksiyonlarını şu şekilde değiştiriyoruz.
static void UsAl(string metin, double d, double p)
{
tarih = DateTime.Now;
Console.WriteLine(metin + Math.Pow(d,p));
Console.WriteLine("Sure : " + (DateTime.Now - tarih).TotalMilliseconds);
}
static void Carp( string metin, double d, double p)
{
tarih = DateTime.Now;
Console.WriteLine(metin + d * p);
Console.WriteLine("Sure : " + (DateTime.Now - tarih).TotalMilliseconds);
}
Şu an fonksiyonlarımız ilk çalıştığı anda güncel tarih ve saat bilgilerini alacak. İkinci aşamada UsAl fonksiyonu verdiğimiz parametrelerdeki değerlere göre üs alma işlemini yapıp sonucu ekrana yazdıracak, Carp fonksiyonu ise yine verilen parametrelere göre çarpma işlemi yapıp sonucu ekrana yazdıracak, üçüncü aşama olarak tekrardan güncel tarih ve saat bilgisini alıp en son aldığı zaman bilgisi ile fonksiyon ilk çalıştığı anda aldığı zaman bilgisi arasındaki farkı hesaplayıp milisaniye cinsinden ekrana yazdıracak. Kodlarımızı tekrar derleyelim ve sonucu görelim fakat bu sefer daha büyük rakamlar kullanalım. ben d=60, p=100 şeklinde değiştirdim

Resimde de görüldüğü gibi basit işlemlerde bir fark yok veya varsa bile sıfıra yakın bir fark oluşuyor. Fakat işlem zorluk derecesi arttıkça aradaki fark da artacaktır. O yüzden her zaman değil ama işlemciyi zorlayacak durumlarda delegate kullanmak faydalı olabilir. Delegate kullanım mantığı biraz pointer(işaretçi) kullanımına benzer fakat aralarında çok önemli bir fark vardır. Yazımızın başında da belirttiğimiz gibi delegate'ler Nesne Yönelimli Programlama tekniğine uygun olarak tasarlanmışlardır ve güvenli bir kullanım sunarlar. Bir sonraki makalemizde temsilcilerin bir başka kullanım yeri olan Events(olaylar)'ları inceleyeceğiz. Programcıların kendi oluşturdukları bileşenlere nasıl event oluşturabileceklerinden bahsedeceğiz.
Bir delegate birden fazla fonksiyona işaret edebilir. Böyle bir durumda delegate çağrıldığında işaret ettiği bütün fonksiyonlar atanma sırası ile çalıştırılacaktır. Bir fonksiyonun delegate aracılığıyla çağırılabilmesi için delegate tanımlanırken belirtilen bütün özelliklere sahip olmalıdır. Aksi takdirde derleme anında hata meydana gelir. İsterseniz önce bir delegate nasıl tanımlanır onu görelim daha sonra küçük bir uygulamayla çalışma anında nasıl davrandığını inceleyelim.
Delegate türü değişkenler Class içerisinde tanımlanabileceği gibi class dışında da tanımlanabilir. işaret edeceği fonksiyon ise yine herhangi bir yerde tanımlanmış olabilir. Bu durumda yani delegate ve onun işaret edeceği fonksiyon farklı class tanımlamaları hatta farklı namespace içindeyse o fonksiyona erişimin olması gereklidir. Yani public bir fonksiyon olmalıdır. Fakat fonksiyon aynı class içinde tanımlanmışsa böyle bir zorunluluk yoktur.
Delegate tanımlamasının herhangi bir yerde yapılabileceğinden bahsetmiştik. Aşağıdaki gibi bir kullanım geçerlidir ve hem derleme anında hem de çalışma anında hata vermez.
using System;
delegate void delegatedeneme (string metin, double d, double p);
namespace DelegateKullanimi
{
class DelegateKullan
{
static void Main(string[] args)
{
}
}
}
Yukarıdaki tanımlamadan parametre olarak 2 tane double türünden değer alan, geriye double türünden bir değer döndüren fonksiyonları temsil etmek üzere bir temsilci tanımladığımızı anlıyoruz. Burada delegate tanımlanırken erişim belirleyicisi kullanılmadığı dikkatinizi çekmiştir. Delegate türü değişlenler sadece "internal" veya "public" olarak tanımlanabilir. Varsayılan türü internal dir. Yani burda olduğu gibi erişim belirleyici belirtilmezse varsayılan değer yazılmış kabul edilir. internal erişim belirleyicisi delegate değişkenine aynı namespace içerisinden erişimi imkanı verir.
Şimdi işi biraz daha ilerletelim. İki tane fonksiyonumuz olsun. Bunlardan biri parametre olarak bir string ve iki tane integer türü değişken alsın ve bu iki sayıyı çarpsın diğeri de yine parametre olarak bir string ve iki integer değişken alsın fakat üs alma işlemi yapsın. Kodlamaya geçelim
static void UsAl(string metin, double d, double p)
{
Console.WriteLine(metin + " " + Math.Pow(d,p));
}
static void Carp(string metin, double d, double p)
{
Console.WriteLine(metin + " " + d * p);
}
Bu fonksiyonları test edelim çalışıp çalışmadıklarını görelim.
static void Main(string[] args)
{
UsAl("Fonksiyon : ",6, 4);
Carp("Fonksiyon : ",6, 4);
Console.ReadLine();
} Kodlarımızı derliyoruz ve gördüğünüz gibi çalışıyor. Zaten çalışmamasını beklemiyorduk. Şimdi gelelim delegate değişkenimize bu fonksiyonları tanıtmaya. Yine "Main(string[] args)" fonksiyonu içinde delegate değişkenimizin türünden bir nesne oluşturuyoruz(delegate türü değişkenlerin Nesne yönelimli programlama tekniğine uygun tasarlandıklarından bahsetmiştik.). Fonksiyonumuz şu hale geldi.
static void Main(string[] args)
{
delegatedeneme temsilci = new delegatedeneme(UsAl);
UsAl("Fonksiyon : ",6, 4);
Carp("Fonksiyon : ",6, 4);
Console.ReadLine();
} Artık temsilci nesnemiz "UsAl(string metin, double d, double p)" fonksiyonunu temsil ediyor. Hatırlarsanız delegate türü değişkenlerin birden fazla fonksiyona işaret edebildiklerinden bahsetmiştik. Bbunu sağlamak için operatorlerden faydalanabiliriz. Delegate değişkenine temsil etmesi için fonksiyon eklemek istediğimizde
temsilci += Carp;
çıkarmak istediğimizde ise
temsilci -= Carp;
komutlarını kullanabiliriz. Şimdi temsilcimize "Carp(string metin, double d, double p)" fonksiyonunu da ekleyelim.
temsilci += Carp; komutunu temsilci tanımlama satırından sonraki satıra ekliyoruz.
Herşey güzel fonksiyonları oluşturduk, temsilcimizi oluşturduk, fonksiyonları temsilcimize tanıttık.. Peki bunları nasıl çalıştıracağız. Bunun iki şekilde yapabiliriz.
1.Yol : Delegate nesnesinin "Invoke()" fonksiyonunu kullanırız.Parametreler bu kısımda girilir.
Örneğin;
temsilci.Invoke("Temsilci : ", 6, 4);
2.Yol : Doğrudan temsilciye parametre vererek temsil edilen fonksiyonları çalıştırabiliriz.
Örneğin;
temsilci("Temsilci : ", 6, 4); Ben ikinci yöntemi kullanmak istiyorum. Main(string[] args) fonksiyonumuzun en son hali şöyle
static void Main(string[] args)
{
delegatedeneme temsilci = new delegatedeneme(UsAl);
UsAl("Fonksiyon : ", 6, 4);
Carp("Fonksiyon : ", 6, 4);
temsilci += Carp;
temsilci("Temsilci : ", 6, 4);
Console.ReadLine();
}Kodlarımızı derleyip çalıştırdığımızda şöyle bir çıktı elde ediyoruz.
Şu an hayal kırıklığı yaşıyor olabilirsiniz ama biraz daha sabrederseniz delegate kullanmanın nasıl bir avantaj olduğunu göreceksiniz. Şuan sadece kod karmaşasını ortadan kaldırmaya yardımcı olduğunu gördük. Peki performans nasıl acaba? Dilerseniz hemen bunu da test edelim. Bunun için class seviyesinde "DateTime" türünde bir değişken oluşturuyoruz.
static DateTime tarih; UsAl ve Carp fonksiyonlarını şu şekilde değiştiriyoruz.
static void UsAl(string metin, double d, double p)
{
tarih = DateTime.Now;
Console.WriteLine(metin + Math.Pow(d,p));
Console.WriteLine("Sure : " + (DateTime.Now - tarih).TotalMilliseconds);
}
static void Carp( string metin, double d, double p)
{
tarih = DateTime.Now;
Console.WriteLine(metin + d * p);
Console.WriteLine("Sure : " + (DateTime.Now - tarih).TotalMilliseconds);
}
Şu an fonksiyonlarımız ilk çalıştığı anda güncel tarih ve saat bilgilerini alacak. İkinci aşamada UsAl fonksiyonu verdiğimiz parametrelerdeki değerlere göre üs alma işlemini yapıp sonucu ekrana yazdıracak, Carp fonksiyonu ise yine verilen parametrelere göre çarpma işlemi yapıp sonucu ekrana yazdıracak, üçüncü aşama olarak tekrardan güncel tarih ve saat bilgisini alıp en son aldığı zaman bilgisi ile fonksiyon ilk çalıştığı anda aldığı zaman bilgisi arasındaki farkı hesaplayıp milisaniye cinsinden ekrana yazdıracak. Kodlarımızı tekrar derleyelim ve sonucu görelim fakat bu sefer daha büyük rakamlar kullanalım. ben d=60, p=100 şeklinde değiştirdim

Resimde de görüldüğü gibi basit işlemlerde bir fark yok veya varsa bile sıfıra yakın bir fark oluşuyor. Fakat işlem zorluk derecesi arttıkça aradaki fark da artacaktır. O yüzden her zaman değil ama işlemciyi zorlayacak durumlarda delegate kullanmak faydalı olabilir. Delegate kullanım mantığı biraz pointer(işaretçi) kullanımına benzer fakat aralarında çok önemli bir fark vardır. Yazımızın başında da belirttiğimiz gibi delegate'ler Nesne Yönelimli Programlama tekniğine uygun olarak tasarlanmışlardır ve güvenli bir kullanım sunarlar. Bir sonraki makalemizde temsilcilerin bir başka kullanım yeri olan Events(olaylar)'ları inceleyeceğiz. Programcıların kendi oluşturdukları bileşenlere nasıl event oluşturabileceklerinden bahsedeceğiz.
C# Bileşen Hazırlama
Öncelikle Visual Studio IDE'sini açıp yeni bir proje oluşturuyoruz. Proje türü olarak da "Windows Form Control Library" seçip bileşenimize bir isim veriyoruz. Bu isim bileşenimizi diğer uygulamalardan çağıracağımız isim olacaktır.

Daha sonra tasarım alanına bir tane Label ve bir tane de ProgressBar nesnesi taşıyoruz. Label nesnesinin ismini "lblBaslik", ProgressBar nesnesinin ismini ise "prgIslem" şeklinde değiştiriyoruz. lblBaslik nesnesinin özelliklerini şu şekilde değiştiriyoruz.
AutoSize = False
BackColor = WhiteSmoke
Font Size = 14,25
ForeColor = Desktop
TextAlign = MiddleCenter
Bunları değiştirdikten sonra lblBaslik nesnesinin text özelliğinde yazan yazıyı siliyoruz. prgIslem nesnesinin özelliklerini ise şu şekilde değiştiriyoruz.
BackColor = MistyRose
ForeColor = DarkSeaGreen
Ben renkleri görmeniz için value değerini değiştiriyorum. Sizin değiştirmenize gerek yok.
Son olarak tasarım alanında boş bir alana tıklayıp UserControl1 nesnesinin özelliklerini değiştiriyoruz.
BackColor = WhiteSmoke
BorderStyle=FixedSingle
Cursor = WaitCursor
Şimdi biraz kod yazalım. Bildiğiniz gibi lblBaslik nesnesinin Text özelliğini boş bırakmıştık. Çünkü bu kısmı hem iki satır halinde tasarlamak istiyorum hemde bileşeni kullanacak kişilerin program içerisinden kod kullanarak kendilerine göre özelleştirebilmelerini sağlayacağız.Öncelikle baslik yazımız için bir özellik tanımlayalım. Buraya yazılanlar lblBaslik nesnesinin üzerinde gösterilecek. Bunun için class içinde kullanılacak string bir değişken tanımlıyoruz.
private string baslik = "İşleminiz devam ediyor. \r\nLütfen Bekleyiniz";
daha sonra lblBaslik nesnesine class dışından da yani bu bileşeni kullanacak diğer programcıların erişebilmeleri için bir özellik tanımlıyoruz.
public string Baslik
{
get { return baslik; }
set { baslik = value; }
}Daha sonra lblBaslik nesnesinin Text'ini değiştirecek bir fonksiyon yazıyoruz.
private void Ayarlar()
{
lblBaslik.Text = baslik;
}Bu fonksiyonu tam olarak istediğimiz gibi çalışması için 2 yere yazıyoruz.
1- oluşturduğumuz Baslik özelliğinin "set" kısmına "baslik = value;"' den sonraki satıra. Her güncellemeden sonra değişikliklerin lblBaslik nesnesinde anında güncellenmesini istiyoruz.
2- Nesne ilk oluşturulduğunda bizim belirlediğimiz metnin Text özelliğinde yer almasını istiyoruz bunun için "UserControl1()" yapıcı fonksiyonunda "InitializeComponent();" satırından sonra "Ayarlar();" satırını ekliyoruz. Şimdi uygulamamızı çalıştıralım ve görelim nasıl olmuş


Şimdi sıra bileşenimizin iş yapacak olan kısımlarını kodlamaya geldi. Yukarıda başlık bilgisi için bir özellik tanımlamıştık. Aynı şekilde 2 tane daha özellik tanımlayacağız. Bunlardan biri prgIslem nesnesinin hangi miktarlarda artacağını belirleyecek diğeri ise bu artışların ne kadar süre aralıkla yapılacağını belirleyecek. Ayrıca varsayılan olarak bir değerde biz veriyoruz. Yine set kısmına "Ayarlar();" satırını ekliyoruz. Artış miktarını değiştireceğimiz özelliği şu şekilde tanımlıyoruz.
private int artismiktari = 5;
public int ArtisMiktarı
{
get { return artismiktari; }set { artismiktari = value; Ayarlar(); }
} Artış hızını değiştireceğimiz özelliği ise şu şekilde tanımlıyoruz.
private int hiz=100;
public int Hiz
{
get { return hiz; }
set { hiz = value; Ayarlar(); }
}
Özellikleri tanımladığımıza göre "Ayarlar()" fonksiyonumuzu güncellemeliyiz. Fonksiyonun son hali
private void Ayarlar()
{
lblBaslik.Text = baslik;
timer1.Interval = hiz;
prgIslem.Step = artismiktari;
}
Şimdi de timer nesnesinin Tick olayını şu kodları yazıyoruz.
private void timer1_Tick(object sender, EventArgs e)
{
if (prgIslem.Value <= prgIslem.Maximum-artismiktari)
{
prgIslem.Value += artismiktari;
}
else
{
prgIslem.Value = 0;
}
}
Bu kısımdaki kodlar hiz özelliği ile belirlenen aralıklarda çalışacak ve her çalışmasında prgIslem nesnesinin Value değerinin maksimum değere ulaşıp ulaşmadığını kontrol edecek. Eğer maksimum değere ulaşılmışsa değeri sıfırlayıp herşeye yeniden başlayacak. Biz durdurana kadar bir döngü halinde devam edecek.
Şimdi bileşenimizi kullanacak olan kişilerin, bileşenimizin çalışmasını başlatabilmesi ve durdurabilmesi için birer fonksiyon oluşturalım.
public void Baslat()
{
this.Visible = true;
}
public void Durdur()
{
this.Visible = false;
}
Bu haliyle bileşenimiz neredeyse tamamlanmış oldu. Birkaç küçük kısım daha kaldı. Yine tasarım alanında boş bir alana tıklıyoruz. UserControl1 nesnesi aktif olması gerekiyor. "Events" kısmında "VisibleChanged" olayını ekliyoruz ve şu şekilde değiştiriyoruz.
private void UserControl1_VisibleChanged(object sender, EventArgs e)
{
if (this.Visible == true)
{
timer1.Enabled = true;
}
else
{
timer1.Enabled = false;
}}
Şimdi yapmamız gereken kullanıcıların bileşenimiz ekrana çıktığında başka bir işlem yapmalarını önlemek. Bunu yapmak için bileşenimiz görünür olduğu sürece başka bir bileşenin aktif olmasını önlemektir. Bu işlemi 2 adımda gerçekletireceğiz.
1.Adım : Başlat fonksiyonu çağırıldığında Focus() fonksiyonunu kullanarak bileşenimizin aktif olmasını sağlamak.
2.Adım : Kullanıcı TAB tuşuna bastığında veya fare ile aynı formda başka bir bileşene tıkladığında (TextBox gibi) o bileşenin aktif olmasını engellemek. Bunu yapmak için tasarım alanında boş bir alana tıklıyoruz ve UserControl1 bileşeninin aktif olmasını sağlıyoruz. Events bölümünde "Leave" event'ını kullanıyoruz. Bu event bileşen üzerindeki Focus() komutuyla sağlanan odaklanma kaybolduğu zaman çalışır. Bizde odaklanma kaybolduğunda tekrar Focus() komutunu kullanarak yeniden bileşenimiz üzerine odaklanma sağlayacağız.
private void UserControl1_Leave(object sender, EventArgs e)
{
this.Focus();
}
Şimdi kodlarımızı tekrar derleyelim. Bileşenimiz gayet güzel bir şekilde çalışıyor. Oluşturduğumuz tüm özellikler (Hiz, Baslik, ArtisMiktarı) üzerinde değişiklik yaptığımızda anında bileşen üzerinde etkili oluyor bir eksiklik var.

Resimde gördüğünüz gibi bizim oluşturduğumuz özellikler seçildiğinde o özelliğin ne işe yaradığı ile ilgili bir açıklama yok. Zorunlu değiliz açıklama eklemek güzel olur. Bunun için özel classlar var onlardan yararlanacağız. Kendi oluşturduğumuz özelliklere açıklama eklemek veya bu özelliklerle ilgili diğer işlemler için "System.ComponentModel" namespace'i içinde bulunun "Description" sınıfını kullanıyoruz. Bu sınıf özellik tanım satırının hemen üstünde kullanılır. "[]" arasında yazılır ve string türde bir parametre alır. Özellik tanımlarımız şu şekilde oldu.
[Description("Bileşenin üzerinde görünecek metni belirler")]
public string Baslik
{
get { return baslik; }
set { baslik = value; Ayarlar(); }
}
[Description("Bileşenin hangi miktarlarda değişeceğini belirler")]
public int ArtisMiktarı
{
get { return artismiktari; }
set { artismiktari = value; Ayarlar(); }
}
[Description("Bileşenin değişim hızını milisaniye cinsinden belirler")]
public int Hiz
{
get { return hiz; }
set { hiz = value; Ayarlar(); }
}
İsterseniz farklı türde ayarlarda var. Bunlardan bazıları şunlar :
[Browsable(false)] : Bu özellik tanımladığınız özelliğin VS.NET IDE sinde Properties tablosunda görünüp görünmeyeceğini belirler.
[Category("YazilimGrubu")] : Bu özellik tanımlanan özelliğin hangi kategori altında görüntüleneceğini belirler. İsterseniz kendiniz bir kategori adı verebilirsiniz.
[DisplayName("YGBaslik")] : Bu özellik tanımlanan özelliğin farklı bir isimle görünmesini sağlar.
Dilerseniz bileşenimize geri dönelim. Tekrar derleyelim ve yaptıklarımızın gerçekten çalışıp çalışmadığını görelim. Evet herşey çok güzel çalışıyor. Dilerseniz özellik tanımlama satırında kullanıcı özelliklere bir değer ataması yaptığında sizin istediğiniz kriterlere uyup uymadığını kontrol edebilirsiniz. VS.NET değer türü bakımından kontrol yapıyor mesela "Hiz" özelliğine rakam içermeyen bir değer girdiğinizde bunu kabul etmiyor. Peki ya siz belirli aralıklar içinde değer girilmesini istiyorsanız mesela "ArtisMiktarı" 0(Sıfır) olarak girilirse ne olacak? işte bunun kontrolünü bizim yapmamız gerekiyor. Bunun için özellik içinde set {} içerisinde bu kontrolü yapmamız gerekiyor. ArtisMiktarı özelliğimizin tanımını şu şekilde değiştiriyoruz.
public int ArtisMiktarı
{
get { return artismiktari; }
set
{
if (value > 0 && value <= 50)
{
artismiktari = value;
}
Ayarlar();
}
}
Bu şekilde bir kontrolle artis miktarının değerini 1-50 arası olacak şekilde sınırladık. Dilerseniz bunu özellik için belirlediğimiz açıklama içinde belirtebilirsiniz. Artık bileşenimiz yayınlanmak için hazır. Umarım faydalı bir makale olmuştur.
C# Yazı Kontrolü ve Yazıcı Ekleme Sihirbazı
Bu fonksiyon sistemde yüklü bir yazıcı olup olmadığını kontrol ediyor. Eğer yüklü bir yazıcı yoksa kullanıcının yeni bir yazıcı yüklemeyi isteyip istemediği soruluyo ve kullanıcı isterse yeni yazıcı ekle sihirbazı çalıştırılıyor. "System.Diagnostics" namespace i projeye eklenmiş olmalıdır.
public bool yazicikontrol()
{
int yazici = System.Drawing.Printing.PrinterSettings.InstalledPrinters.Count;
DialogResult dr;
if (yazici == 0)
{
dr = MessageBox.Show(this, "Aktif yazıcı bulunamadı.Yazıcınızın düzgün çalıştığından emin olun\r\n" +
"veya donanım sürücülerini yeniden yüklemeyi deneyin. \r\n" +
"Sürücüleri şimdi yüklemek için Evet'i tıklayın.\r\n" +
"Sürücüleri daha sonra yüklemek istiyorsanız Hayır'ı tıklayın.", "Yazıcı Bulunamadı", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
if (dr == DialogResult.Yes)
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "rundll32.exe";
psi.CreateNoWindow = true;
psi.Arguments = "shell32.dll,SHHelpShortcuts_RunDLL AddPrinter";
psi.UseShellExecute = true;
Process.Start(psi);
return false;
}
else if (dr == DialogResult.No)
{
return false;
}
}
return true;
}
public bool yazicikontrol()
{
int yazici = System.Drawing.Printing.PrinterSettings.InstalledPrinters.Count;
DialogResult dr;
if (yazici == 0)
{
dr = MessageBox.Show(this, "Aktif yazıcı bulunamadı.Yazıcınızın düzgün çalıştığından emin olun\r\n" +
"veya donanım sürücülerini yeniden yüklemeyi deneyin. \r\n" +
"Sürücüleri şimdi yüklemek için Evet'i tıklayın.\r\n" +
"Sürücüleri daha sonra yüklemek istiyorsanız Hayır'ı tıklayın.", "Yazıcı Bulunamadı", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
if (dr == DialogResult.Yes)
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "rundll32.exe";
psi.CreateNoWindow = true;
psi.Arguments = "shell32.dll,SHHelpShortcuts_RunDLL AddPrinter";
psi.UseShellExecute = true;
Process.Start(psi);
return false;
}
else if (dr == DialogResult.No)
{
return false;
}
}
return true;
}
Kaydol:
Yorumlar (Atom)


