Değerli Okurlarım Merhabalar,
Kullanıcı web kontrolleri (web user
control) kendi
içlerinde birden fazla kontrolü barındırabilen komposit tipteki
görsel bileşenlerdir. Asp.Net 1.0/1.1 den veri var olan kullanıcı web
kontrollerini çoğunlukla,
birden fazla sayfada kullandığımız durumlarda (hatta aynı sayfada bir
çok yerde aynı kontrol kümelerini kullanmak istediğimizde) düşünür
ve geliştiririz. Bu kontroller tek bir yerde durdukları için
güncelleştirilmeleri halinde, kullanıldıkları tüm sayfalara ilgili
değişiklikler yansıyacaktır. Güncelleme kolaylığı, kullanıcı web
kontrollerini tercih etmemizin en büyük
nedenlerinden birisidir. Ancak bu kontroller bir açıdan bakıldığında,
herhangibir web sayfasına eklenen web sunucu kontrollerinden (web server
control) yada html sunucu kontrollerinden (html server control) çok da farklı
düşünülmemelidir. Nasıl ki bir web sunucu kontrolünün özellikleri
(properties) ve
olayları(events) oluyorsa bir web kullanıcı kontrolününde özellikleri ve olayları
olabilir. Nihayetinde, bir kullanıcı tanımlı web kontrolü aslında
System.Web.UI.UserControl sınıfından türerler ve
kullanıldığı sayfanın bir parçası olarak sunucu tarafında nesne bazında
ele alınırlar. Dolayısıyla kullanıldıkları sayfada yakalanabilecek
olayları ve kullanılabilecek özellikleri olabilir. Hatta bir web
kontrolünü nasıl dinamik olarak oluşturabiliyorsak bir kullanıcı web
kontrolünü de dinamik olarak oluşturabilir ve sayfanın o anki içeriğine
ekleyebiliriz. İşte bu makalemizde daha çok bu konular üzerinde durmaya
çalışacağız. Temel olarak aşağıdaki üç maddede duracağız.
- Özellik (Property) kullanımı
- Kullanıcı web kontrollerini dinamik
oluşturma
- Olay (Event) kullanımı
1. Özellik (Property) Kullanımı
Kullanıcı web kontrollerinin
aslında System.Web.UI.Control tipinden türeyen sınıflar şeklinde ifade
edilebileceğinden bahsetmiştik. Bu nedenle kullanıcı web kontrollerine özellik ekleyebiliriz. Bu özellikler yardımıyla örneğin
bir kullanıcı tanımlı kontrol içerisindeki bileşenlerin bazı
özelliklerine dışarıdan erişebilir hatta değiştirebiliriz. Dilerseniz
örnek bir senaryo üzerinden gidelim. Aşağıdaki ekran çıktısına sahip olan
bir web user control' ümüz olduğunu düşünelim.

AdresBilgisi.ascx;
<%@
Control
Language="C#" AutoEventWireup="true"
CodeFile="AdresBilgisi.ascx.cs" Inherits="AdresBilgisi" %>
<table>
<tr>
<td >İl</td>
<td ><asp:DropDownList ID="ddlIl"
runat="server" ></asp:DropDownList></td>
</tr>
<tr>
<td >İlçe</td>
<td ><asp:TextBox ID="txtIlce"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td >Cadde</td>
<td ><asp:TextBox ID="txtCadde"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td >Sokak</td>
<td ><asp:TextBox ID="txtSokak"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td >Posta Kodu</td>
<td ><asp:TextBox ID="txtPostakodu"
runat="server"></asp:TextBox></td>
</tr>
</table> |
AdresBilgisi.ascx.cs;
public partial
class AdresBilgisi : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
string[] iller = new string[] {
"Istanbul", "Ankara", "Izmir" };
foreach (string il in iller)
ddlIl.Items.Add(il);
}
} |
AdresBilgisi isimli kullanıcı tanımlı
web kontrolümüz içerisinde basit olarak İl, İlçe, Cadde, Sokak,
PostaKodu gibi bilgiler tutulmaktadır. Elbette burada sade düşünmek
zorunda olduğumuzdan kontrolü mümkün olduğunca basit tasarladık. Normal
şartlar altında bu kontrole doğrulama (validation) bileşenlerini ilave
etmek, il ve ilçe gibi bilgileri bir birleri ile ilişkili olacak şekilde
gerekli veri kümelerinden çekmek gibi işlemleri göz ardı ediyoruz.
Odaklanacağımız nokta bu kontrol için kendi özelliklerimizi yazmak ve
kullanmak olacak. Şimdi bu kontrollerden iki tanesini kullanacağımız
aşağıdaki ekran görüntüsüne sahip bir web sayfası olduğunu düşünelim.

Aslında senaryomuz oldukça tanıdık
gelecektir. Bir alış veriş sitesinde, teslimat adresi ve fatura adresi
bilgilerinin aynı olması halinde aynı tipten iki web user control
arasında nasıl iletişim kuracağız. (Çok doğal olarak burada bir
CheckBox kontrolü kullanıp teslima adresinin fatura adresi olraakta
kullanılacağını belirtebilir ve işi tek bir kullanıcı tanımlı web
kontrol ile halledebileceğimizi düşünebiliriz. Ancak böyle bir durumdada
farklı bir Fatura adresi girilmesi mümkün olmayacaktır.) İşte bu nokta bize web user control
içerisindeki kontrollerin dışarıdan erişebilir olmasını sağlayacak
özellikler gerekecektir. Bu amaçla, AdresBilgisi isimli kullanıcı
tanımlı web kontrollümüze aşağıdaki gibi özellikler eklememiz
gerekecektir. Özelliklerimiz kullanıcı web kontrolü içerisindeki
bileşenlerin Text, SelectedIndex gibi özelliklerinin değerlerini dış
ortama açmaktan sorumludur.
public int Il
{
get { return ddlIl.SelectedIndex; }
set { ddlIl.SelectedIndex = value; }
}
public string Ilce
{
get { return txtIlce.Text; }
set { txtIlce.Text = value; }
}
public string Cadde
{
get { return txtCadde.Text; }
set { txtCadde.Text = value; }
}
public string Sokak
{
get { return txtSokak.Text; }
set { txtSokak.Text = value; }
}
public string PostaKodu
{
get { return txtPostakodu.Text; }
set { txtPostakodu.Text = value; }
} |
Artık AdresBilgisi kontrolü
içerisindeki üyelere kod tarafında erişebilir, dahada önemlisi
düşündüğümüz senaryoyu gerçekleyebiliriz. Bunun için tek yapmamız
gereken default.aspx.cs içerisinde aşağıdaki kod parçasını yazmaktır.
protected void
btnAyniAdres_Click(object sender, EventArgs e)
{
AdresBilgisi2.Il
= AdresBilgisi1.Il;
AdresBilgisi2.Ilce
= AdresBilgisi1.Ilce;
AdresBilgisi2.Cadde
= AdresBilgisi1.Cadde;
AdresBilgisi2.Sokak
= AdresBilgisi1.Sokak;
AdresBilgisi2.PostaKodu
= AdresBilgisi1.PostaKodu;
} |
Şimdi örneğimizi çalıştıralım ve
Teslimat adresi bilgilerini girdikten sonra Fatura İçin Aynı Adresi
Kullan düğmesine basalım.
İlk Durum;

Düğmeye basıldıktan sonra;

Sonuçta, AdresBilgisi1 isimli kullanıcı
web kontrolü
içerisindeki bileşenlere ait değerler AdresBilgisi2 isimli kullanıcı web kontrolü içerisinde
bileşenlere aynen gönderilmiştir. Dolayısıyla hem kullanıcıyı aynı
bilgileri girme zahmetinden kurtardık hemde aynı web user control' e ait
birden fazla örnek arasında nasıl veri transferi yapabileceğimizi
aydınlatmış olduk. Gelelim ikinci konumuza.
2. Kullanıcı web kontrollerini dinamik
oluşturma
Çalışma zamanında (run time) web
kontrollerini dinamik olarak oluşturmak hatta bunları aynı event
metodlarına yönlendirmek özellikle portal tarzı sistemlerde önemlidir.
Benzer davranışı kullanıcı web kontrolleri içinde gerçekleştirebiliriz.
Burada dikkat edilmesi gereken husus, kullanıcı tanımlı web kontrolünün
ele alınacağı sayfa içerisinde kayıt edilerek (register) bildirilmesi
gerektiğidir. Bunun için Register direktifinden yararlanabiliriz.
Örneğin AdresBilgisi.ascx kullanıcı tanımlı web kontrolünü dinamik
olarak default2.aspx isimli bir sayfada kullanmak istediğimizi
düşünelim. İlk olarak Register direktifini aşağıdaki gibi eklemeliyiz.
<%@ Page
Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs"
Inherits="Default2" %>
<%@
Register
Src="~/AdresBilgisi.ascx"
TagName="Adres"
TagPrefix="adr"
%> |
Aslında bir web user control herhangi
bir sayfaya eklendiği zaman, bu direktif otomatik olarak eklenmektedir.
Bizim şu anki amacımız kontrolden bir kaç tanesini dinamik olarak
oluşturup ilgili web sayfasına eklemek olduğundan kod tarafında ilgili
kontrol tipine erişebilmemiz gerekmektedir. Bu nedenle ilgili web
kullanıcı kontrolünü register ettik. Dinamik olarak gerçekleştirilecek
işlemler için sayfanın Page_Init olay metodunu tercih edebiliriz.
(Bu olay metodu bir web sayfasının yaşam döngüsünde genellikle
kontrolün dinamik olarak oluşturulması istendiği durumlarda tercih
edilmektedir. Elbetteki bu bir zorunluluk değildir. İstenildiğinde
Page_PreInit yada Page_Load gibi event metodlarınıda dinamik kontrol
oluşturma amacıyla göz önüne alabiliriz.)
protected void
Page_Init(object sender, EventArgs e)
{
AdresBilgisi kontrol1=(AdresBilgisi)LoadControl("AdresBilgisi.ascx");
AdresBilgisi kontrol2 = (AdresBilgisi)LoadControl("AdresBilgisi.ascx");
kontrol1.Ilce = "İlçe giriniz...";
kontrol2.PostaKodu = "90000";
phKontroller.Controls.Add(kontrol1);
phKontroller.Controls.Add(kontrol2);
} |
Dikkat ederseniz, AdresBilgisi isimli
kullanıcı web kontrollerini öncelikle yüklememiz gerekmektedir. Bu işlem
için LoadControl metodu kullanılmıştır. Bu metod o anki sayfaya
(Page) ait bir metoddur ve geriye Control tipinden bir nesne
örneği döndürmektedir. Kontrolü bu şekilde yükledikten sonra hemen
ilgili taşıyıcı nesneye eklemeyi tercih edebiliriz elbette. Ancak biz
kontrolümüzün Ilce, PostaKodu gibi özelliklerinede kod içerisinde
erişmek istediğimizden doğru bir tip dönüşümüne ihtiyacımız vardır. Bu
nedenle LoadControl ile elde edilen Control nesnesi AdresBilgisi tipine
cast operatörü yardımıyla dönüştürülmektedir. Örneğimizi
çalıştırdığımızda phKontroller isimli PlaceHolder bileşeninin Controls
koleksiyonuna, AdresBilgisi kontrollerinin aşağıdaki gibi eklendiği
gözlemlenebilir.

3. Olay (Event) Kullanımı
Kullanıcı web kontrollerini, sıradan
bir web sunucu kontrolü olarak düşünmeye çalıştığımızda olaylara sahip
olabileceğini de söyleyebiliriz. Örneğin bir Button nesnesi bir web
sayfasına eklendiğinde ve bu nesneye mouse ile basıldığında Click event'
i (eğer yüklenmiş ise) aktif hale gelir. Web tabanlı
uygulamaların doğası gereği bu olaya ilişkin metodlar, her ne kadar
sayfanın içerisindeki üyeler olsalarda hemen çalıştırılmazlar. Bunun
sebebi, sunucu tarafında ilgili web sayfasının nesnel olarak üretilmesi
sırasında çalışan yaşam döngüsü (page life cycle) dür. İstemci
aslında bir düğmeye bastığında, sayfa istemci tarayıcı penceresinden
sunucuya doğru içeriği ile birlikte gönderilir (Bu işlemi genellikle
Postback olarak adlandırıyoruz). Bunun üzerine sunucu tarafında
gönderilen sayfanın bir örneği oluşturulur ve çok genel hatları ile
aşağıdaki yaşam döngüsü çalışır.
Page_PreInit
Page_Init
Page_Load
Button için Click / Change Olay Metodları
Page_PreRender
Page_UnLoad
Peki biz kendi geliştirdiğimiz
kullanıcı web kontrollerine olay eklemek istersek ne olur. Öncelikle
olarak sayfanın yaşam döngüsü aşağıdakine benzer bir sırada
işleyecektir.
Aspx sayfası ilk talep edildiğinde;
Default3.aspx
Page_PreInit
Urun.ascx Init
Urun.ascx Init
Default3.aspx Page_Init
Default3.aspx Load
Urun.ascx Load
Urun.ascx Load
Urun.ascx UnLoad
Urun.ascx UnLoad
Default3.aspx Page_UnLoad |
Sayfadaki Web User Control
içerisinden bir olay tetiklendiğinde;
Default3.aspx
Page_PreInit
Urun.ascx Init
Urun.ascx Init
Default3.aspx Page_Init
Default3.aspx Load
Urun.ascx Load
Urun.ascx Load
Default3.aspx içinde çalışan web user control olayı
Urun.ascx UnLoad
Urun.ascx UnLoad
Default3.aspx Page_UnLoad |
Yaşam döngüsünün işleyişini kısaca
inceledikten sonra kullanıcı web kontrolleri için olayları nasıl
yazabileceğimize bir bakalım. İlk olarak, bir temsilci (delegate)
tanımlanır. Temsilcinin amacı, ilgili olay tetiklendiğinde devreye
girecek olan olay metodunun yapısını tanımlamak ve çalışma zamanında bu
metodun adresini işaret etmektir. Sonrasında ise bir event tanımlanır.
Tanımladığımız event, user control' ü kullandığımız sayfalarda ele
alınabilecektir. Bir başka deyişle, kullanıcı web kontrolü içerisinde
tanımlanan olay gerçekleştiğinde, sayfa içerisinde yazılan olay metodu
devreye girecektir. Genel olarak olay metodları iki parametre ile
çalışırlar. İlk parametre çoğunlukla olayı meydana getiren nesneyi
referans eder. İkinci parametre ise, olay metoduna olay ile ilgili bir
takım bilgiler aktarabilir. Örneğin EventArgs gibi. Dolayısıyla kendi
parametre sınıflarımızı yazıp, olay metodu içerisine bilgi
taşıyabiliriz. Şimdi dilerseniz bu işlemleri bir senaryo üzerinden
incelemeye çalışalım.
Örnek senaryomuzda, Urun.ascx isimli
bir web user control nesnemiz var. Bu nesne içerisinde dinamik olarak
oluşturulan CheckBox kontrollerinde günler tutulmakta. Kullanıcı
ürünlerin teslim edilebileceği günleri seçebilmektedir. Kontrol üzerinde
yer alan düğmeye basıldığında ise, SecilenleriAl isimli bir olay manual
olarak tetiklenmektedir. Önemli olan nokta, SecilenleriAl isimli olayın
kontrolün kullanıldığı sayfa içerisinde yakalanabileceği ve ele
alınabileceğidir. Bu kontrol içerisinde tanımladığımız temsilcimiz kendi
içerisinde KontrolBilgileri isimli bir sınıfı olay parametresi olarak
kullanmaktadır. Bir başka deyişle KontrolBilgileri sınıfını EventArgs
sınıfı gibi düşünebiliriz. Önce KontrolBilgileri sınıfını tasarlayarak
işe başlayalım.
public class
KontrolBilgileri
{
private List<string> m_Kontroller;
public List<string> Kontroller
{
get { return m_Kontroller; }
}
public KontrolBilgileri(PlaceHolder ph)
{
m_Kontroller = new List<string>();
for (int i = 0; i <
ph.Controls.Count; i++)
{
if
(ph.Controls[i] is CheckBox)
{
CheckBox currentChk=ph.Controls[i] as CheckBox;
if (currentChk.Checked)
m_Kontroller.Add(currentChk.Text);
}
}
}
} |
KontrolBilgileri sınıfının görevi, olay
metodu içerisine, kullanıcı web kontrolünde seçili olan CheckBox
bileşenlerinin Text bilgilerini string tipinden elemanlar taşıyan
generic bir koleksiyon şeklinde döndürmektir. Olay içine bilgi taşıyacak
sınıfımızı tasarladıktan sonra kullanıcı web kontrolümüzü aşağıdaki gibi
geliştirebiliriz.
Urun.ascx;
<%@
Control
Language="C#" AutoEventWireup="true" CodeFile="Urun.ascx.cs"
Inherits="Urun" %>
<asp:PlaceHolder ID="phGunler" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Button ID="btnIsaretle" runat="server" Text="Isaretle"
OnClick="btnIsaretle_Click" /> |
Urun.ascx.cs;
public partial
class Urun : System.Web.UI.UserControl
{
public delegate void SecilenleriAlHandler(KontrolBilgileri
args);
public event SecilenleriAlHandler SecilenleriAl;
protected void Page_Load(object sender, EventArgs args)
{
string[] gunler = new string[] {
"Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma",
"Cumartesi", "Pazar" };
foreach (string gun in gunler)
{
CheckBox
chkBox = new CheckBox();
chkBox.ID =
gun;
chkBox.Text =
gun;
phGunler.Controls.Add(chkBox);
LiteralControl lc = new LiteralControl("<br/>");
phGunler.Controls.Add(lc);
}
}
protected void btnIsaretle_Click(object sender, EventArgs e)
{
if (SecilenleriAl
!= null)
SecilenleriAl(new
KontrolBilgileri(phGunler));
}
} |
Kontrolümüzde, SecilenleriAlHandler
isimli temsilci(delegate) ve SecilenleriAl isimli olay (event) üyesi yer
almaktadır. btnIsaretle isimli düğmemize ait Click olay metounda,
SecilenleriAl isimli bir olay kontrolü kullanan bir sayfa tarafından
yüklenmiş ise manual olarak tetiklenmektedir. Bu şu anlama gelir. Eğer
kontrolü kullandığımız bir web sayfasında, bu kontrole ait SecilenleriAl
isimli bir olay yüklenmiş ise, bununla ilişkili olay metodu
çalıştırılacaktır. Bu amaçla default3.aspx isimli örnek bir sayfada
aşağıdaki kodları geliştirelim.
default3.aspx;


default3.aspx.cs;
public partial
class Default3 : System.Web.UI.Page
{
protected void
Secilenler(KontrolBilgileri kb)
{
for (int i = 0; i <
kb.Kontroller.Count;
i++)
Response.Write(kb.Kontroller[i]+"<br/>");
}
} |
Uygulamamız çalıştırdığımızda, user
control üzerinde bazı seçenekleri işaretlediğimizde ve düğmeye
bastığımızda o sayfa üzerinde tanımladığımız Secilenler isimli olay
metodunun çalıştığını ve seçilen günlerin ekrana yazıldığını
görebiliriz.

Dikkat edilmesi gereken bir nokta
vardır. Çoğunlukla kontrolleri dinamik olarak oluşturup bir web
sayfasına eklediğimizde bu kontrollerin hepsini tek bir olay metoda
yönlendirebiliriz. İlgili olay metodu içerisinde hangi kontrolden
gelindiğini anlamak için ise genellike object tipinden gelen ve ismi
çoğunlukla sender olarak bilinen değişkeni ilgili tipe cast ederiz.
Benzer yapıyı Urun.ascx kontrolü için düşündüğümüzde, SecilenleriAl
isimli olay metoduna aynı işlevselliği sağlayacak eklentiyi yapamız
gerekecektir. Bunun için temsilciyi, olayı tetikleyen metoddaki çağrıyı
ve sınıf üzerindeki kontrole ait olay metodunu aşağıdaki gibi
değiştirmemiz yeterli olacaktır.
Urun.ascx.cs' de temsilci;
| public
delegate void SecilenleriAlHandler(object
gonderen,KontrolBilgileri
args); |
Urun.ascx.cs' de olayı tetikleyen
button_Click metodu;
protected void
btnIsaretle_Click(object
sender,
EventArgs e)
{
if (SecilenleriAl != null)
SecilenleriAl(this,new
KontrolBilgileri(phGunler));
} |
default3.aspx.cs' deki Secilenler
olay metod;
protected void
Secilenler(object
sender,KontrolBilgileri
kb)
{
for (int i = 0; i < kb.Kontroller.Count; i++)
Response.Write(kb.Kontroller[i]+"<br/>");
} |
Bu değişiklik bize, kontrole ait olay
metodu içerisinde hangi web kullanıcı kontrolünün tetiklendiğini
algılama imkanı verecektir. Böylece birden fazla web kullanıcı
kontrolünü aynı olay metoduna yönlendirdiğimizde her birinin
özelliklerini ve üyelerini aynı metod içerisinde ele alabiliriz. Örneğin
Urun.ascx içerisinde günler dışında ekstradan bilgi girilebilecek
notların olduğu bir TextBox olduğunu ve bu TextBox' ın içeriğine dış
ortamdan erişebilmemizi sağlayan read only bir özellik eklediğimizi
düşünelim.
public string
Notlar
{
get{return txtNot.Text;}
} |
Default3.aspx sayfasında Urun.ascx
kontrolünden örneğin 2 tane olduğunu ve bunların aynı olay metoda
yönlendirildiğini göz önüne. Bu durumda ilgili olay metodu içerisinde,
hangi kontrol tarafından bir tetikleme olduğunu tespit edebilir. Çünkü
artık olayı tetikleyen nesneyi taşıyan bir parametremiz vardır.
Dolayısıyla bu parametre üzerinden ilgili Notlar özelliğe geçebilir ve
hangi kontrolden gelindiyse onun notlarını alabiliriz.
protected void
Secilenler(object sender,KontrolBilgileri kb)
{
Urun
urn = (Urun)sender;
Response.Write(urn.Notlar
+ "<br/>");
for (int i = 0; i < kb.Kontroller.Count; i++)
Response.Write(kb.Kontroller[i]+"<br/>");
} |

Bu makalemizde kullanıcı web
kontrollerini daha etkin şekilde nasıl kullanabileceğimizi incelemeye
çalıştık. Aslında çıkış noktamız bir web kullanıcı kontrolünü normal bir
web sunucu kontrolüne benzer bir sınıf olarak düşünmekti. Bu sayede
kullanıcı web kontrollerine özellik, olay ekleyebileceğimizi ve dinamik
olarak çalışma zamanında oluşturabileceğimizi gördük. Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşünceye
dek hepinize mutlu günler dilerim.
Örnek kod için tıklayın.
Burak Selim ŞENYURT
selim@bsenyurt.com