Skip to content

7. ASP sunucu bileşenleri - 1

7.1. Introduction

Bu bölümde, ASP.NET'te kullanıcı arayüzünü oluşturmak için önerilen teknolojiyi açıklıyoruz. Web sunucusu tarafından bir .aspx sayfasının işlenmesinde iki ayrı aşama olduğunu biliyoruz:

  1. öncelikle sayfanın denetleyicisi çalıştırılır. Bu denetleyici, ya .aspx sayfasının kendisinde (WebMatrix çözümü) ya da ayrı bir dosyada (Visual Studio.NET çözümü) bulunan koddan oluşur.
  2. Ardından, .aspx sayfasının sunum kodu çalıştırılarak, istemciye gönderilecek HTML koduna dönüştürülür.

Image

ASP.NET, sayfanın sunum kodunu yazmak için üç etiket kütüphanesi sunar:

  1. klasik HTML etiketleri. Şimdiye kadar kullandığımız etiketler bunlardır.
  2. HTML sunucu etiketleri
  3. webform etiketleri

Hangi etiket kütüphanesi kullanılırsa kullanılsın, sayfa denetleyicisinin rolü değişmez. Sayfa denetleyicisi, sunum kodunda görünen dinamik parametrelerin değerini hesaplamalıdır. Şimdiye kadar bu dinamik parametreler basitti: [String] türünde nesnelerdi. Dolayısıyla, sunum kodunda bir <%=nom%> etiketi varsa:

  • sayfa denetleyicisi, [String] türünde bir [nom] değişkeni tanımlar ve değerini hesaplar
  • sayfa denetleyicisi işini tamamladığında ve HTML yanıtını oluşturmak için sunum kodu çalıştırıldığında, <%=nom%> etiketi denetim kodu tarafından hesaplanan değerle değiştirilir

Denetleyici/sunum ayrımının keyfi olduğu ve aynı sayfada denetleyici koduyla sunum kodunun birleştirilebileceği bilinmektedir. Bu yöntemin neden tavsiye edilmediğini açıkladık ve denetleyici/sunum ayrımına uymaya devam edeceğiz.

[HTML serveur] ve [WebForms] etiketleri, sunum koduna basit [String] nesnesinden daha karmaşık nesneler eklemeye olanak tanır. Bu, bazen gerçekten yararlı olabilir. Liste içeren bir form örneğini ele alalım. Bu liste, müşteriye şuna benzer bir HTML koduyla sunulmalıdır:

<select name="uneListe" size="3">
    <option value="opt1">option1</option>
    <option value="opt2">option2</option>
    <option value="opt3" selected>option3</option>
</select>

Listenin içeriği ve seçilecek seçenek dinamik öğelerdir ve bu nedenle sayfa denetleyicisi tarafından oluşturulmalıdır. Bu sorunla daha önce karşılaştık ve sunum koduna şu etiketi ekleyerek sorunu çözdük:

<%=uneListeHTML%>

Bu etiket, [uneListeHTML] değişkeninin [String] değeriyle değiştirilecektir. Denetleyici tarafından hesaplanan bu değer, listede yer alan HTML koduna, yani c.a.d'e karşılık gelmelidir. "<select name=..>...</select>". Bunu yapmak özellikle zor değildir ve sayfanın sunum kısmına doğrudan kod oluşturma kodunu eklemekten kaçınan zarif bir çözüm gibi görünür. Aksi takdirde, bu kısma testler içeren bir döngü eklenmesi gerekecek ve bu da sunum kısmını büyük ölçüde "kirletecektir". Bununla birlikte, bu yöntemin bir dezavantajı vardır. Bir sayfanın denetim ve sunum kısmına ayrılması, aynı zamanda iki yetki alanını birbirinden ayırmaya da yarar:

  • sayfa denetleyicisinden sorumlu .NET geliştiricisi
  • sayfanın sunum kısmından sorumlu olan grafik tasarımcının yetki alanı

Burada, listenin HTML kodunun oluşturulmasının denetleyiciye aktarıldığını görüyoruz. Grafik tasarımcı, listenin "görsel" görünümünü değiştirmek için bu HTML kodunda değişiklik yapmak isteyebilir. Bu durumda, [contrôleur] bölümünde çalışmak zorunda kalacak ve dolayısıyla kendi yetki alanının dışına çıkacak; bu da koda istemeden hataların girilmesi riskini beraberinde getirecektir.

Sunucu etiket kütüphaneleri bu sorunu çözer. Bu kütüphaneler, bir HTML listesini temsil eden bir nesne sunar. Dolayısıyla, [WebForms] kütüphanesi şu etiketi sunar:

<asp:ListBox id="uneListe" runat="server"></asp:ListBox>

Bu etiket, sayfa denetleyicisi tarafından işlenebilen [ListBox] türünde bir nesneyi temsil eder. Bu nesne, HTML listesindeki çeşitli seçenekleri temsil etmek ve seçilen seçeneği belirtmek için özelliklere sahiptir. Sayfa denetleyicisi bu nedenle bu özelliklere uygun değerleri atayacaktır. Sunum kısmı çalıştırıldığında,

<asp:ListBox id="uneListe" runat="server"></asp:ListBox>

etiketi, [uneListe] ve c.a.d nesnelerini temsil eden HTML koduyla değiştirilecektir. "<select ..>...</select>" koduna dönüştürülecektir. Şu an için önceki yöntemle temel bir fark yoktur; tek fark, nesne yönelimli bir kodlama yönteminin kullanılmasıdır ki bu ilginç bir noktadır. Listenin "görünümünü" değiştirmek isteyen grafik tasarımcımıza geri dönelim. Sunucu etiketleri, ilgili HTML nesnesinin görsel görünümünü belirlemeye olanak tanıyan stil özniteliklerine (BackColor, Bordercolor, BorderWidth, ...) sahiptir. Böylece şöyle yazabiliriz:


                <asp:ListBox id="ListBox1" runat="server" BackColor="#ffff99"></asp:ListBox></P>

Bunun avantajı, grafik tasarımcının bu değişiklikleri yapmak için sunum kodunda kalabilmesidir. Bu, önceki yönteme kıyasla kesin bir avantajdır. Sunucu etiket kütüphaneleri, sayfaların sunum kısmının oluşturulmasında kolaylıklar sağlar; bu kısma önceki bölümlerde kullanıcı arayüzü adını vermiştik. Bu bölümün amacı, bunları tanıtmaktır. Göreceğiz ki bu kütüphaneler bazen takvimler veya veri kaynaklarına bağlı tablolar gibi karmaşık nesneler sunar. Bu kütüphaneler genişletilebilir niteliktedir (c.a.d); kullanıcı kendi etiket kütüphanesini oluşturabilir. Böylece, bir sayfada bir başlık şeridi oluşturan bir etiket geliştirebilir. Bu etiketi kullanan tüm sayfalar da aynı başlık şeridine sahip olacaktır.

Bir etiket için oluşturulan HTML çıktısı, istemci tarayıcısının türüne göre uyarlanır. Tarayıcı, web sunucusuna bir istek gönderdiğinde, başlıkları arasında HTTP ile birlikte, [User-Agent: xx] başlığını da gönderir; burada [xx], istemciyi tanımlar. İşte bir örnek:

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

Bu bilgi sayesinde web sunucusu, istemcinin yeteneklerini, özellikle de hangi HTML kod türünü işleyebildiğini öğrenebilir. Zaman içinde HTML dilinin birçok sürümü ortaya çıkmıştır. Yeni tarayıcılar bu dilin en güncel sürümlerini desteklerken, eski tarayıcılar bunu yapamaz. İstemcinin kendisine gönderdiği HTTP [User-Agent:] başlığına göre, sunucu istemcinin anlayabileceği bir HTML sürümünü gönderecektir. Bu, ilginç ve kullanışlı bir fikirdir; çünkü böylece geliştirici, uygulamasının hangi tür tarayıcıda çalışacağı konusunda endişelenmek zorunda kalmaz.

Son olarak, Visual Studio.NET, WebMatrix gibi gelişmiş IDE araçları, web arayüzünün “Windows tarzında” tasarlanmasına olanak tanır. Bu araçlar zorunlu olmasa da, geliştiriciye önemli bir yardım sağlar. Geliştirici, web arayüzünü bu arayüze yerleştirdiği grafik bileşenler yardımıyla tasarlar. Arayüzdeki her bir bileşenin özelliklerine doğrudan erişebilir ve bunları istediği gibi ayarlayabilir. Bu özellikler, arayüzün sunumuna ilişkin HTML kodunda, bileşenin <asp:> etiketinin özniteliklerine dönüştürülür. Geliştirici açısından bunun avantajı, her bir etiketin özniteliklerinin listesini veya sözdizimini hatırlamak zorunda olmamasıdır. Bu, ASP.NET tarafından sunulan sunucu etiket kütüphanelerini tam olarak bilmediğinizde önemli bir avantajdır. Bu sözdizimini öğrendikten sonra, bazı geliştiriciler grafik tasarım aşamasına geçmeden doğrudan sayfanın sunum kodunda etiketleri yazmayı tercih edebilir. Bu durumda bir IDE artık gerekli değildir. Basit bir metin düzenleyici yeterlidir. Çalışma tarzına bağlı olarak, odak noktası bileşenlere (bir IDE kullanımı) veya etiketlere (bir metin düzenleyicinin kullanımı) kayar. Bu iki terim birbirinin eşdeğeridir. Bileşen, sayfanın kontrol kodu tarafından işlenecek nesnedir. IDE, tasarım aşamasında bileşenin özelliklerine erişim sağlar. Bu özelliklere verilen değerler, sunum kodundaki bileşen etiketinin özniteliklerine anında yansıtılır. Çalıştırma aşamasında, sayfanın kontrol kodu bileşeni işler ve bazı özelliklerine değerler atar. Sunum kodu ise, bir yandan tasarım aşamasında ilgili sunucu etiketi için belirlenen öznitelikleri, diğer yandan da kontrol kodu tarafından hesaplanan bileşen özelliklerinin değerlerini kullanarak bileşenin HTML kodunu oluşturacaktır.

7.2. Örneklerin yürütme bağlamı

Sunucu bileşenlerine dayalı web arayüzlerinin tasarımını, yürütme bağlamı çoğunlukla aşağıdaki gibi olan programlarla açıklayacağız:

  1. web uygulaması, F formunu içeren tek bir P sayfasından oluşacak,
  2. istemci ilk isteğini doğrudan bu P sayfasına yapacaktır. Bu, bir tarayıcıyla P sayfasının URL'sini istemekten ibarettir. Dolayısıyla, bu P URL'si üzerinden GET numaralı bir istek yapılacaktır. Sunucu, P sayfasını ve dolayısıyla içinde bulunan F formunu gönderecektir,
  3. kullanıcı bu formu doldurup gönderecek (c.a.d); bu, tarayıcının F formunu sunucuya göndermesini sağlayacak bir eylemdir. Tarayıcının POST işlemi her zaman P sayfasına yönelik olacaktır. Sunucu, kullanıcının eylemi sonucunda içeriği değiştirilmiş olabilecek F formunu içeren P sayfasını yeniden gönderecektir.
  4. Ardından 2. ve 3. adımlar tekrarlanacaktır.

Bu, oldukça özel bir yürütme sürecidir ve bu sürecin dışında, aşağıda açıklanan bazı kavramlar artık işlev görmez. Artık, çok sayfalı bir uygulamanın "uygulama denetleyicisi" olarak adlandırdığımız belirli bir sayfa tarafından kontrol edildiği MVC mimarisi bağlamında değiliz. Bu tür bir mimaride, formların POST istekleri, formların kendilerini değil, denetleyiciyi hedef alır. Ancak göreceğimiz üzere, sunucu bileşenleriyle bir form oluşturmak, bu formun kendisine gönderilmesi anlamına gelir.

7.3. Label bileşeni

7.3.1. Kullanım

<asp:label> etiketi, bir sayfanın sunum koduna dinamik bir metin eklemeye olanak tanır. Dolayısıyla, şimdiye kadar kullandığımız <%=değişken%> etiketinden daha fazlasını yapmaz. Bu ilk etiketi incelemek, sunucu etiketlerinin işleyişini anlamamızı sağlayacaktır. Bir kontrol bölümü ([form1.aspx.vb]) ve bir sunum bölümü ([form1.aspx]) içeren bir sayfa oluşturuyoruz. Amaç, saati görüntülemektir:

Image

Bu konu 2. bölümde daha önce ele alınmıştı; okuyucu, bu konunun nasıl ele alındığını öğrenmek isterse o bölüme başvurabilir. [form1.aspx] sunum kodu şu şekildedir:


<%@ page src="form1.aspx.vb" inherits="form1" AutoEventWireup="false" %>
<HTML>
    <HEAD>
        <title>Webforms</title>
    </HEAD>
    <body>
        <asp:Label Runat="server" ID="lblHeure" />
    </body>
</HTML>

<asp:label> etiketini tanıtıyoruz. Etiket kütüphanelerinde, [runat="server"] özniteliği zorunludur. ID özniteliği bileşeni tanımlar. Denetleyici, bu tanımlayıcıyla bileşene başvurmalıdır. [form1.aspx.vb] denetleyicisinin kodu şöyledir:


Imports System.Web.UI.WebControls

Public Class form1
    Inherits System.Web.UI.Page

    Protected lblHeure As Label

    Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Init
        ' geçerli sorguyu sayfa klasöründeki request.txt dosyasına kaydeder
        Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt"
        Me.Request.SaveAs(requestFileName, True)
    End Sub

    Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' saati lblHeure dosyasına ekler
        lblHeure.Text = "Il est " + Date.Now.ToString("T")
    End Sub

End Class

Denetleyici, [System.Web.UI.WebControls.Label] türündeki [lblHeure] nesnesine bir değer atamalıdır. <asp:> etiketleriyle görüntülenen tüm nesneler, [System.Web.UI.WebControls] ad alanına aittir. Dolayısıyla bu ad alanını sistematik olarak içe aktarabiliriz:


Imports System.Web.UI.WebControls

[Label] nesnesinin çeşitli özellikleri vardır; bunlardan [Text] özelliği, ilgili <asp:label> etiketiyle görüntülenecek metni temsil eder. Burada, bu özelliğe geçerli saati atıyoruz. Bunu, her zaman yürütülen denetleyicinin [Form_Load] yordamında yapıyoruz. Yine her zaman çalıştırılan, ancak [Form_Load] yordamından önce çalıştırılan [Form_Init] yordamında, istemcinin isteğini uygulama klasöründeki [request.txt] dosyasına kaydediyoruz. Sunucu etiketleri kullanan sayfaların işleyişinin bazı yönlerini anlamak için bu dosyayı inceleme fırsatımız olacak.

[Label] nesnesi birçok özellik, yöntem ve olaya sahiptir. Okuyucunun, bunları keşfetmek için [Label] sınıfına ilişkin belgeleri okuması önerilir. Bundan sonra da durum hep böyle olacaktır. Her etiket için, yalnızca ihtiyacımız olan birkaç özelliği sunacağız.

7.3.2. Testler

Dosyaları (form1.aspx, form1.aspx.vb) bir <application-path> klasörüne yerleştirip Cassini'yi (<application-path>,/form1) parametreleriyle başlatıyoruz. Ardından [http://localhost/form1/form1.aspx] URL'sini çağırıyoruz. Aşağıdaki sonucu elde ediyoruz:

Image

Tarayıcı tarafından alınan HTML kodu şöyledir:

<HTML>
    <HEAD>
        <title>Webforms</title>
    </HEAD>
    <body>
        <span id="lblHeure">Il est 19:39:37</span>
    </body>
</HTML>

Görüldüğü gibi, sunucu etiketi


        <asp:Label Runat="server" ID="lblHeure" />

şu HTML koduna dönüştürüldüğü görülüyor:

        <span id="lblHeure">Il est 19:39:37</span>

<span> ve </span> etiketleri arasına yerleştirilen, [lblHeure] nesnesinin [Text] özelliğidir. İstemci tarafından yapılan ve [request.txt]'te saklanan istek şöyledir:

GET /form1/form1.aspx HTTP/1.1
Cache-Control: max-age=0
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

Her şey gayet normal.

7.3.3. WebMatrix ile uygulamayı oluşturmak

[form1.aspx] sayfasının sunum kodunu elle oluşturduk. Bu yöntem, etiketleri biliyorsanız kullanılabilir. Bu durumda, kullanıcı arayüzünü oluşturmak için basit bir metin düzenleyici yeterlidir. Başlangıçta, ihtiyaç duyulan etiketlerin sözdizimini bilmediğiniz için genellikle otomatik kod oluşturma özelliğine sahip bir grafik tasarım aracı gereklidir. Şimdi aynı uygulamayı WebMatrix aracıyla oluşturuyoruz. WebMatrix başlatıldıktan sonra, [File/New File] seçeneğini seçiyoruz:

Image

ASP.NET adlı bir sayfa oluşturuyoruz. Önceki sihirbazı onayladıktan sonra, [form2.aspx] sayfasının tasarım penceresi karşımıza çıkıyor:

Image

Image

WebMatrix'in, sayfanın kontrol kodunu ve sunum kodunu aynı dosyaya, bu durumda [form2.aspx]'e yerleştirdiğini hatırlatırız. [All] sekmesi, bu metin dosyasının içeriğini gösterir. Şu anda dosyanın boş olmadığını görebiliriz:

Image

Bu tür araçların dezavantajı, genellikle gereksiz kod üretmeleridir. Burada da durum böyledir; WebMatrix, bir form oluşturmayacağımız halde <form> etiketini üretmiştir... Ayrıca, belgede <title> etiketinin bulunmadığı da görülebilir. Bu iki sorunu hemen gidererek aşağıdaki yeni sürümü elde ediyoruz:

Image

Kontrol kodu olarak adlandırdığımız kod, <script> ve </script> etiketleri arasına yerleştirilecek; bu da kontrol ve sunum olmak üzere iki kod türü arasında en azından görsel bir ayrım sağlar. Arayüzümüzü tasarlamak için [Design] sekmesine geri dönüyoruz. Tasarım penceresinin solundaki araç penceresinde bir bileşen listesi mevcuttur:

Image

Araç penceresi, iki tür bileşene erişim sağlar:

  • <asp:> etiketlerine dönüşen [WebControls] bileşenleri
  • klasik HTML etiketlerine dönüştürülen [HTML Elements] bileşenleri. Bununla birlikte, bir HTML etiketinin özniteliklerine [runat="server"] özniteliği eklenebilir. Bu durumda, HTML etiketine ve özniteliklerine, temsil ettiği HTML etiketinin özelliklerini taşıyan bir nesne aracılığıyla denetleyici tarafından erişilebilir. Bu etiketlere daha önce sunucu HTML etiketleri adını vermiştik.

[WebControls] denetim listesindeki [Label] bileşenine çift tıklayalım. [Design] sekmesinde şu sonuç elde edilir:

Image

[All] sekmesinde kod şu şekilde değişmiştir:

<%@ Page Language="VB" %>
<html>
<head>
    <title>webforms</title>
</head>
<body>
    <asp:Label id="Label1" runat="server">Label</asp:Label>
</body>
</html>

İlk olarak, <script> etiketinin kaybolduğu görülebilir. Bir <asp:label> etiketi oluşturulmuştur. Bu etiketin adı [Label1] ve değeri [Label]'tir. Bu iki değeri değiştirmek için [Design] sekmesine geri dönelim. [Label] bileşenine bir kez tıklayarak, sağ alt köşede bu bileşenin özellikler penceresini açalım:

Image

Okuyucunun [Label] nesnesinin özelliklerine bakması önerilir. Burada iki özellik ilgimizi çekiyor:

  • Metin: Etiketin görüntülemesi gereken metindir – boş bir dize giriyoruz (c.a.d. hiçbir şey)
  • ID: Bu, nesnenin kimliğidir; buraya lblHeure yazıyoruz

[Design] sekmesi şu şekilde olur:

Image

ve [All]'in kodu şu şekilde olur:

<%@ Page Language="VB" %>
<html>
<head>
    <title>webforms</title>
</head>
<body>
    <asp:Label id="lblHeure" runat="server"></asp:Label>
</body>
</html>

Sayfanın sunum kısmı tamamlandı. Geriye, saati [lblHeure]'in [Text] özelliğine yerleştiren kontrol kodunu yazmak kaldı. [All] sekmesine aşağıdaki kodu ekliyoruz:


<%@ Page Language="VB" %>

<script runat="server">
    Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' saati lblHeure dosyasına kaydeder
        lblHeure.Text = "Il est " + Date.Now.ToString("T")
    End Sub
</script>

<html>
<head>
    <title>webforms</title>
</head>
<body>
    <asp:Label id="lblHeure" runat="server"></asp:Label>
</body>
</html>

Denetleyici kodunda, [lblHeure] nesnesinin daha önce yapıldığı gibi tanımlanmadığına dikkat edilmelidir:


    Protected lblHeure As New System.Web.UI.WebControls.Label

Aslında, sunum bölümündeki tüm <asp:> sunucu bileşenleri, denetleyici kod bölümünde örtük olarak tanımlanmaktadır. Dolayısıyla, bunları da tanımlamak derleme hatasına neden olur; bu hata, nesnenin zaten tanımlandığını belirtir. Çalıştırmaya hazırız. [View/Start] seçeneğini veya [F5] kısayolunu kullanıyoruz. Cassini, aşağıdaki parametrelerle otomatik olarak başlatılır:

Image

Bu değerleri kabul ediyoruz. Sistemin varsayılan tarayıcısı, [http://localhost/form2.aspx] URL'sini istemek üzere otomatik olarak başlatılır. Aşağıdaki sonucu elde ederiz:

Image

Bundan sonra, yazacağımız kısa programların oluşturulmasını ve test edilmesini kolaylaştırmak için esas olarak WebMatrix aracını kullanacağız.

7.4. Literal bileşeni

7.4.1. Kullanım

<asp:literal> etiketi, <asp:label> etiketi gibi bir sayfanın sunum koduna dinamik bir metin eklemeye olanak tanır. Ana özniteliği [Text]'tir; bu, sayfanın HTML akışına olduğu gibi eklenecek metni temsil eder. HTML akışına eklemek istediğimiz metne biçimlendirme uygulamak istemiyorsak, bu etiket yeterlidir. Nitekim, [Label] sınıfı [BorderColor, BorderWidth, Font, ...] gibi öznitelikler sayesinde biçimlendirme yapılmasına izin verirken, [Literal] sınıfında bu tür özniteliklerin hiçbiri bulunmamaktadır. Okuyucu, [Label] bileşenini bir [Literal] bileşeniyle değiştirerek önceki örneği aynen kullanabilir.

7.5. Button bileşeni

7.5.1. Kullanım

<asp:Button> etiketi, bir forma [Submit] türünde bir düğme eklemeye olanak tanır; bu düğme, Windows uygulamalarında bulunanlara benzer bir olay yönetimi özelliğini beraberinde getirir. Burada bu konuyu daha ayrıntılı olarak ele alacağız. Aşağıdaki [form3.aspx] sayfasını oluşturuyoruz:

Image

WebMatrix ile oluşturulan bu sayfa üç bileşene sahiptir:

No
ad
tür
özellikler
rol
1
Button1
Düğme
text=Düğme1
gönder düğmesi
2
Button2
Düğme
text=Düğme2
gönder düğmesi
3
lblInfo
Etiket
text=
bilgilendirme mesajı

WebMatrix tarafından bu bölüm için oluşturulan kod şöyledir:

<%@ Page Language="VB" %>
<script runat="server">
</script>
<html>
<head>
    <title>asp:button</title>
</head>
<body>
    <form runat="server">
        <p>
            <asp:Button id="Button1" runat="server" Text="Bouton1"></asp:Button>
            <asp:Button id="Button2" runat="server" Text="Bouton2"></asp:Button>
        </p>
        <p>
            <asp:Label id="lblInfo" runat="server"></asp:Label>
        </p>
    </form>
</body>
</html>

Sayfanın grafik tasarımında kullanılan [Button] ve [Label] bileşenlerini <asp:> etiketleri içinde görüyoruz. Otomatik olarak oluşturulan <form runat="server"> etiketine dikkat edelim. Bu, bir sunucu etiketi olan HTML ve c.a.d'tir; HTML ise klasik bir etikettir, ancak denetleyici tarafından işlenebilen bir nesne olarak temsil edilir. <form> etiketinin kodu, denetleyicinin bu nesneye vereceği değerden yola çıkılarak oluşturulacaktır.

Kodun denetleyici kısmına, sayfanın [Init] olayını yöneten [Page_Init] yordamını ekleyelim. Buraya, istemcinin isteğini [request.txt] dosyasına kaydeden kodu yerleştiriyoruz. Düğmelerin işleyişini anlamak için buna ihtiyacımız olacak.

<script runat="server">
    Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) 
        ' geçerli isteği request.txt dosyasına kaydeder
        Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt"
        Me.Request.SaveAs(requestFileName, True)
    End Sub
</script>

Yukarıda, [Page_Init] prosedürünün tanımının arkasına [Handles MyBase.Init] maddesini eklemediğimize dikkat edilmelidir. Aslında, [Page] nesnesinin [Init] olayı, [Page_Init] adlı bir varsayılan işleyiciye sahiptir. Bu işleyici adı kullanılırsa, [Handles Page.Init] cümlesi gereksiz hale gelir. Ancak bu cümleyi eklemek bir hata oluşturmaz.

7.5.2. Testler

Uygulamayı WebMatrix altında [F5] ile başlatıyoruz. Aşağıdaki sayfayı görüyoruz:

Image

Tarayıcı tarafından alınan HTML kodu şöyledir:

<html>
<head>
    <title>asp:button</title>
</head>
<body>
    <form name="_ctl0" method="post" action="form3.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNTY0NjIwMjUwOzs+2mcnJczeuvF2PEfvmtv7uiUhWUw=" />

        <p>
            <input type="submit" name="Button1" value="Bouton1" id="Button1" />
            <input type="submit" name="Button2" value="Bouton2" id="Button2" />

        </p>
        <p>
            <span id="lblInfo"></span>
        </p>
    </form>
</body>
</html>

Aşağıdaki noktalara dikkat edelim:

  • <form runat="server"> etiketinin HTML etiketine dönüştüğü
    <form name="_ctl0" method="post" action="form3.aspx" id="_ctl0">

[method="post"] ve [action="form3.aspx"] olmak üzere iki öznitelik belirlenmiştir. Bu özniteliklere farklı değerler verilebilir mi? Bu konuyu biraz ileride açıklığa kavuşturmaya çalışacağız. Şu anda, formun [form3.aspx] URL'sine gönderileceğini not edelim. [name, id] adlı iki öznitelik daha belirlenmiştir. Çoğu zaman bunlar göz ardı edilir. Ancak sayfa, tarayıcı tarafında çalıştırılan JavaScript kodu içeriyorsa, <form> etiketindeki [name] özniteliği yararlıdır.

  • <asp:button> etiketleri, HTML düğme etiketlerine dönüştü. Bu düğmelerden herhangi birine tıklandığında, [_ctl10] formunun [form3.aspx] URL'sine "post" işlemi gerçekleştirilir.
  • <asp:label> etiketi, HTML <span> etiketine dönüştü
  • [__VIEWSTATE] adlı gizli bir alan, tuhaf bir değerle oluşturulmuştur:
<input type="hidden" name="__VIEWSTATE" value="dDwxNTY0NjIwMjUwOzs+2mcnJczeuvF2PEfvmtv7uiUhWUw=" />

Bu alan, müşteriye gönderilen formun durumunu kodlanmış bir biçimde temsil eder. Bu durum, formun tüm bileşenlerinin değerini temsil eder. [__VIEWSTATE] formun bir parçası olduğu için, değeri de geri kalanlarla birlikte sunucuya gönderilecektir. Bu, sunucunun formun hangi bileşeninin değerinin değiştiğini bilmesini ve gerektiğinde kararlar almasını sağlayacaktır. Bu kararlar, "TextBox adlı bileşenin değeri değişti" türünde olaylar şeklinde olacaktır.

7.5.3. İstemciden gelen istekler

Tarayıcıda [form3.aspx] sayfası görüntülendikten sonra, sayfayı yeniden isteyelim ve tarayıcının bu sayfayı almak için gönderdiği isteğe bakalım. Uygulamamızın bu isteği, uygulama klasöründeki [request.txt] dosyasına kaydettiğini hatırlayalım:

GET /form3.aspx HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

Burada klasik bir GET örneği var. Şimdi tarayıcıdaki sayfadaki [Bouton1] düğmesine tıklayalım. Görünüşe göre hiçbir şey olmuyor. Oysa formun gönderildiğini biliyoruz. Bunu, sayfanın HTML kodu gösteriyor. Bu durum, [request.txt]'in yeni içeriği ile de doğrulanıyor:

POST /form3.aspx HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Content-Length: 80
Content-Type: application/x-www-form-urlencoded
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form3.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

__VIEWSTATE=dDwxNTY0NjIwMjUwOzs%2B2mcnJczeuvF2PEfvmtv7uiUhWUw%3D&Button1=Bouton1

İlk başlık HTTP, müşterinin POST'i [/form3.aspx] URL'sine gönderdiğini açıkça göstermektedir. Son satır, gönderilen değerleri göstermektedir:

  • gizli alanın değeri __VIEWSTATE
  • tıklanan düğmenin değeri

[Bouton2]'e tıklarsak, tarayıcı tarafından gönderilen değerler şunlardır:

__VIEWSTATE=dDwxNTY0NjIwMjUwOzs%2B2mcnJczeuvF2PEfvmtv7uiUhWUw%3D&Button2=Bouton2

Gizli alanın değeri her zaman aynıdır, ancak gönderilen değer [Button2]'tir. Böylece sunucu, hangi düğmenin kullanıldığını anlayabilir. Sunucu, bu bilgiyi kullanarak, sayfa yüklendikten sonra sayfa tarafından işlenebilecek bir olayı tetikleyecektir.

7.5.4. Button nesnesinin Click olayını yönetme

Bir .aspx sayfasının nasıl çalıştığını hatırlayalım. Bu sayfa, [Page] sınıfından türetilmiş bir nesnedir. Türetilmiş sınıfa [unePage] diyelim. Sunucu bu tür bir sayfa için bir istek aldığında, new unePage(...) işlemiyle [unePage] türünde bir nesne oluşturulur. Ardından sunucu, sırasıyla [Init] ve [Load] adlı iki olay üretir. [unePage] nesnesi, [Page_Init] ve [Page_Load] olay işleyicilerini sağlayarak bunları yönetebilir. Ardından başka olaylar da oluşturulacaktır. Buna daha sonra tekrar değineceğiz. İstemcinin isteği bir POST ise, sunucu bu POST'i tetikleyen düğmenin [Click] olayını oluşturacaktır. [unePage] sınıfı bu olay için bir işleyici tanımlamışsa, bu işleyici çağrılacaktır. Bu mekanizmayı WebMatrix örneği üzerinden inceleyelim. [form3.aspx]'in [Design] sekmesinde, [Bouton1] düğmesine çift tıklayalım. Böylece otomatik olarak [Code] sekmesine, [Button1_Click] adlı prosedürün gövdesine yönlendiriliriz. Daha iyi anlamak için [All] sekmesine gidip kodun tamamına bakalım. Aşağıdaki değişiklikler yapılmıştır:

<%@ Page Language="VB" %>
<script runat="server">

...
    Sub Button1_Click(sender As Object, e As EventArgs)

    End Sub

</script>
<html>
...
<body>
    <form runat="server">
...
            <asp:Button id="Button1" onclick="Button1_Click" runat="server" Text="Bouton1"></asp:Button>
    </form>
</body>
</html>

[onclick="Button1_Click"] adlı yeni bir öznitelik, [Button1]'in <asp:Button> etiketine eklendi. Bu öznitelik, [Button1] nesnesindeki [Click] olayını işleyecek yordamı belirtir; burada bu yordam [Button1_Click]'tir. Artık bu yordamı yazmamız yeterli:

    Sub Button1_Click(sender As Object, e As EventArgs)
        ' 1 numaralı düğmeye tıklama
        lblInfo.Text="Vous avez cliqué sur [Bouton1]"
    End Sub

Bu prosedür, [lblInfo] etiketine bir bilgi mesajı ekler. Aynı işlemi [Bouton2] düğmesi için de uygulayarak aşağıdaki yeni [form3.aspx] sayfasını elde ederiz:

<%@ Page Language="VB" %>
<script runat="server">

    Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
        ' geçerli isteği request.txt sayfa klasörüne kaydeder
        Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt"
        Me.Request.SaveAs(requestFileName, True)
    End Sub

    Sub Button1_Click(sender As Object, e As EventArgs)
        ' 1 numaralı düğmeye tıklayın
        lblInfo.Text="Vous avez cliqué sur [Bouton1]"
    End Sub

    Sub Button2_Click(sender As Object, e As EventArgs)
        ' 2 numaralı düğmeye tıklayın
        lblInfo.Text="Vous avez cliqué sur [Bouton2]"
    End Sub

</script>
<html>
<head>
    <title>asp:button</title>
</head>
<body>
    <form runat="server">
        <p>
            <asp:Button id="Button1" onclick="Button1_Click" runat="server" Text="Bouton1"></asp:Button>
            <asp:Button id="Button2" onclick="Button2_Click" runat="server" Text="Bouton2" BorderStyle="None"></asp:Button>
        </p>
        <p>
            <asp:Label id="lblInfo" runat="server"></asp:Label>
        </p>
    </form>
</body>
</html>

[F5] komutunu çalıştırarak aşağıdaki sayfayı elde ediyoruz:

Image

Alınan HTML koduna bakarsak, sayfanın önceki sürümündekine göre herhangi bir değişiklik olmadığını görürüz:

<html>
<head>
    <title>asp:button</title>
</head>
<body>
    <form name="_ctl0" method="post" action="form3.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNTY0NjIwMjUwOzs+2mcnJczeuvF2PEfvmtv7uiUhWUw=" />

        <p>
            <input type="submit" name="Button1" value="Bouton1" id="Button1" />
            <input type="submit" name="Button2" value="Bouton2" id="Button2" />
        </p>
        <p>
            <span id="lblInfo"></span>
        </p>
    </form>
</body>
</html>

[Bouton1]'e tıklarsak, şu yanıtı alırız:

Image

Bu yanıt için alınan HTML kodu şöyledir:

<html>
<head>
    <title>asp:button</title>
</head>
<body>
    <form name="_ctl0" method="post" action="form3.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNTY0NjIwMjUwO3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDU+Oz47bDx0PHA8cDxsPFRleHQ7PjtsPFZvdXMgYXZleiBjbGlxdcOpIHN1ciBbQm91dG9uMV07Pj47Pjs7Pjs+Pjs+Pjs+4oO98Vd244kj0lPMXReWOwJ1WW0=" />

        <p>
            <input type="submit" name="Button1" value="Bouton1" id="Button1" />
            <input type="submit" name="Button2" value="Bouton2" id="Button2" />
        </p>
        <p>
            <span id="lblInfo">Vous avez cliqué sur [Bouton1]</span>
        </p>
    </form>
</body>
</html>

Gizli alan [__VIEWSTATE]'in değerinin değiştiğini görebiliriz. Bu, [lblInfo] bileşeninin değerindeki değişikliği yansıtmaktadır.

7.5.5. ASP.NET uygulamasının yaşam döngüsü olayları

ASP.NET belgeleri, bir uygulamanın yaşam döngüsü boyunca sunucu tarafından oluşturulan olayların listesini vermektedir:

  • uygulamanın aldığı ilk istek sırasında, uygulamanın [HttpApplication] nesnesi üzerinde [Start] olayı oluşturulacaktır. Bu olay, uygulamanın [global.asax] dosyasındaki [Application_Start] yordamıyla işlenebilir.

Ardından, alınan her istek için tekrarlanacak bir dizi olayla karşılaşacağız:

  • istek bir oturum jetonu göndermediyse, yeni bir oturum başlatılır ve istekle ilişkili [Session] nesnesi üzerinde bir [Start] olayı oluşturulur. Bu olay, uygulamanın [global.asax] dosyasındaki [Session_Start] yordamı tarafından işlenebilir.
  • Sunucu, [HttpApplication] nesnesi üzerinde [BeginRequest] olayını oluşturur. Bu olay, uygulamanın [global.asax] dosyasındaki [Application_BeginRequest] yordamıyla işlenebilir.
  • sunucu, istekle talep edilen sayfayı yükler. Bir [Page] nesnesi oluşturur ve ardından bu nesne üzerinde iki olay üretir: [Init] ve ardından [Load]. Bu iki olay, sayfanın [Page_Init] ve [Page_Load] prosedürleri tarafından yönetilebilir.
  • Alınan gönderilen değerlere dayanarak, sunucu başka olaylar da oluşturacaktır: değeri değişen bir [TextBox] bileşeni için [TextChanged], değeri değişen bir radyo düğmesi için [CheckedChanged], seçili öğesi değişen bir liste için [SelectedIndexChanged], ... Sunacağımız her bir sunucu bileşeni için başlıca olaylardan bahsetme fırsatımız olacak. O adlı bir nesne üzerindeki her E olayı, O_E adlı bir yordam tarafından işlenebilir.
  • Yukarıdaki olayların işlenme sırası garanti edilmez. Bu nedenle, işleyiciler bu sıra hakkında herhangi bir varsayımda bulunmamalıdır. Ancak, POST olayını tetikleyen düğmenin [Click] olayının en son işleneceği kesindir.
  • Sayfa hazır hale geldiğinde, sunucu bunu istemciye gönderecektir. Bundan önce, sayfanın [Page_PreRender] yordamı tarafından işlenebilen [PreRender] olayını oluşturur.
  • HTML yanıtı istemciye gönderildikten sonra, sayfa bellekten kaldırılır. Bu sırada [Unload] ve [Disposed] olmak üzere iki olay oluşturulur. Sayfa, bu olayları kullanarak kaynakları serbest bırakabilir.

Uygulama, bir istemci isteği dışında da olaylar alabilir:

  • Uygulamadaki bir [Session] nesnesi üzerindeki [End] olayı, bir oturum sona erdiğinde gerçekleşir. Bu, bir sayfanın kodunun açık talebi üzerine ya da oturuma tanınan süre dolduğu için meydana gelebilir. [global.asax] dosyasındaki [Session_End] yordamı bu olayı yönetir. Bu yordamda genellikle [Session_Start]'te elde edilen kaynaklar serbest bırakılır.
  • Uygulamanın [HttpApplication] nesnesindeki [End] olayı, uygulama sonlandırıldığında gerçekleşir. Bu durum özellikle web sunucusu kapatıldığında meydana gelir. [global.asax] dosyasındaki [Application_End] yordamı bu olayı yönetir. Bu yordamda genellikle [Application_Start]'te elde edilen kaynaklar serbest bırakılır.

Aşağıdaki noktalar dikkat çekicidir:

  • önceki olay modeli, klasik HTTP istemci-sunucu iletişimlerine dayanır. Bu durum, değiş tokuş edilen HTTP başlıklarına bakıldığında açıkça görülür.
  • Önceki olayların işlenmesi her zaman sunucu tarafında gerçekleşir. Bir düğmeye tıklama, elbette sunucu tarafındaki bir JavaScript komut dosyası tarafından işlenebilir. Ancak bu durumda söz konusu olan bir sunucu olayı değildir ve burada ASP.NET'ten bağımsız bir teknolojiyle karşı karşıyayız.

Olaylar, ister sunucu tarafında (sunucu bileşenleriyle ilgili olaylar) ister tarayıcı tarafında JavaScript komut dosyaları tarafından işlensin, ne zaman işlenir?

Bir açılır liste örneğini ele alalım. Kullanıcı bu listede seçili öğeyi değiştirdiğinde, olay (seçili öğenin değişmesi) işlenebilir veya işlenmeyebilir; işlenirse de farklı zamanlarda işlenebilir.

  • Hemen işlenmesini istiyorsak iki çözümümüz vardır:
    • Javascript komut dosyası kullanılarak tarayıcı tarafından işlenebilir. Bu durumda sunucu devreye girmez. Bunun mümkün olabilmesi için sayfanın, sayfada bulunan değerlerle yeniden oluşturulabilmesi gerekir.
    • Olay, sunucu tarafından işlenebilir. Bunun için tek bir çözüm vardır: formun işlenmek üzere sunucuya gönderilmesi gerekir. Dolayısıyla burada [submit] adlı bir işlem söz konusudur. Bu durumda, [DropDownList] adlı bir sunucu bileşeni kullanıldığını ve [AutoPostBack] özniteliğinin [true] olarak ayarlandığını göreceğiz. Bu, açılır listeden seçilen öğenin değişmesi durumunda formun derhal sunucuya gönderilmesi gerektiği anlamına gelir. Bu durumda sunucu, [DropDownList] nesnesi için, "seçili öğenin değişmesi" olayı meydana gelir gelmez bir [submit] oluşturmakla görevli bir JavaScript işlevine bağlı HTML kodunu üretir. Bu [submit], formu sunucuya gönderecek ve formda, [post]'in açılır listedeki bir seçim değişikliğinden kaynaklandığını belirtmek için gizli alanlar yer alacaktır. Sunucu daha sonra, sayfanın işleyebileceği [SelectedIndexChanged] olayını oluşturacaktır.
    • Eğer bu olayı işlemek isteniyor ancak hemen değilse, [DropDownList] sunucu bileşeninin [AutoPostBack] özniteliği [false] olarak ayarlanır. Bu durumda sunucu, [DropDownList] nesnesi için, ilişkili bir JavaScript işlevi olmayan klasik bir <select> listesinin kodu olan HTML'i oluşturur. Kullanıcı açılır listedeki seçimini değiştirdiğinde hiçbir şey olmaz. Ancak, kullanıcı örneğin [submit] düğmesiyle formu gönderdiğinde, sunucu seçimde bir değişiklik olduğunu algılayabilecektir. Nitekim, sunucuya gönderilen formun, gönderilen formun tüm öğelerinin durumunu kodlanmış bir biçimde temsil eden [__VIEWSTATE] adlı gizli bir alanı içerdiğini görmüştük. Sunucu, istemci tarafından gönderilen yeni formu aldığında, açılır listede seçili öğenin değişip değişmediğini kontrol edebilir. Değişmişse, sayfanın yönetebileceği [SelectedIndexChanged] olayını oluşturur. Bu mekanizmayı öncekinden ayırt etmek için bazı yazarlar, "seçim değişikliği" olayının tarayıcıda gerçekleştiğinde "önbelleğe alındığını" belirtir. Bu olay, genellikle [submit] düğmesine tıklandıktan sonra tarayıcının sunucuya formu göndermesiyle birlikte işlenir.
    • Son olarak, olayı işlemek istemiyorsak, [DropDownList] sunucu bileşeninin [AutoPostBack] özniteliğini [false] olarak ayarlarız ve [SelectedIndexChanged] olay işleyicisini yazmayız.

Olay işleme mekanizmasını anladıktan sonra, geliştirici bir web uygulamasını bir Windows uygulaması gibi tasarlamayacaktır. Nitekim, bir Windows uygulamasındaki açılır menüdeki seçim değişikliği, bu menünün bulunduğu formun görünümünü anında değiştirmek için kullanılabilirken, bir web uygulamasında bu olayın hemen işlenmesi, formun sunucuya "post" edilmesini ve dolayısıyla istemci ile sunucu arasında bir ağ iletişimi gerektirdiği için daha fazla tereddüt yaratacaktır. Bu nedenle, sunucu bileşenlerinin [AutoPostBack] özelliği varsayılan olarak [false] olarak ayarlanmıştır. Ayrıca, web sunucusu tarafından müşteriye gönderilen formda otomatik olarak oluşturulan JavaScript komut dosyalarına dayanan [AutoPostBack] mekanizması, yalnızca müşteri tarayıcısının JavaScript komut dosyalarının çalıştırılmasına izin verdiğinden emin olunması durumunda kullanılabilir. Bu nedenle formlar genellikle şu şekilde oluşturulur:

  • formun sunucu bileşenlerinin [AutoPostBack] özelliği, [false] olarak ayarlanır
  • formda, formun [POST] işlemini gerçekleştirmekle görevli bir veya daha fazla düğme bulunur
  • sayfanın denetleyici koduna, yönetmek istediğimiz olayların işleyicileri yazılır; bu genellikle düğmelerden birindeki [Click] olayıdır.

7.6. TextBox bileşeni

7.6.1. Kullanım

<asp:TextBox> etiketiyle, bir sayfanın sunum koduna bir giriş alanı eklenebilir. Aşağıdaki sunumu elde etmek için bir [form4.aspx] sayfası oluşturuyoruz:

Image

4321 WebMatrix ile oluşturulan bu sayfa aşağıdaki bileşenleri içerir:

no
ad
tür
özellikler
rol
1
TextBox1
TextBox
AutoPostback=true
Text=
giriş alanı
2
TextBox2
TextBox
AutoPostback=false
Metin=
giriş alanı
3
lblInfo1
Etiket
text=
[TextBox1] içeriğine ilişkin bilgilendirme mesajı
3
lblInfo2
Etiket
text=
[TextBox2] içeriği hakkında bilgi mesajı

WebMatrix tarafından bu bölüm için oluşturulan kod şöyledir:

<%@ Page Language="VB" %>
<script runat="server">
</script>
<html>
<head>
    <title>asp:textbox</title>
</head>
<body>
    <form runat="server">
        <p>
            Texte 1 :
            <asp:TextBox id="TextBox1" runat="server" AutoPostBack="True"></asp:TextBox>
        </p>
        <p>
            Texte 2 :
            <asp:TextBox id="TextBox2" runat="server"></asp:TextBox>
        </p>
        <p>
            <asp:Label id="lblInfo1" runat="server"></asp:Label>
        </p>
        <p>
            <asp:Label id="lblInfo2" runat="server"></asp:Label>
        </p>
    </form>
</body>
</html>

[Design] sekmesinde, [TextBox1] bileşenine çift tıklayalım. Bu nesnenin [TextChanged] olay yöneticisinin iskeleti oluşturulur ([All] sekmesi):

<%@ Page Language="VB" %>
<script runat="server">

    Sub TextBox1_TextChanged(sender As Object, e As EventArgs)
    End Sub
</script>
<html>
...
<body>
...
            <asp:TextBox id="TextBox1" runat="server" AutoPostBack="True" OnTextChanged="TextBox1_TextChanged"></asp:TextBox>
        </p>
....
    </form>
</body>
</html>

[OnTextChanged="TextBox1_TextChanged"] özniteliği, <asp:TextBox id="TextBox1"> etiketine, [TextChanged] olayının işleyicisini [TextBox1] olarak belirtmek üzere eklenmiştir. Şimdi yazacağımız prosedür [TextBox1_Changed]'tir.

    Sub TextBox1_TextChanged(sender As Object, e As EventArgs)
      ' metni değiştir
      lblInfo1.text=Date.now.Tostring("T") + ": evt [TextChanged] sur [TextBox1]. Texte 1=["+textbox1.Text+"]"
    End Sub

Prosedürde, [lblInfo1] etiketine, olayı bildiren ve [TextBox1]'in içeriğini belirten bir mesaj yazıyoruz. Aynı işlemi [TextBox2] için de yapıyoruz. Olayların işlenmesini daha iyi takip edebilmek için saati de belirtiyoruz. [form4.aspx]'in nihai kodu şöyledir:

<%@ Page Language="VB" %>
<script runat="server">

    Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
        ' geçerli isteği sayfanın klasöründeki request.txt dosyasına kaydeder
        Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt"
        Me.Request.SaveAs(requestFileName, True)
    End Sub

    Sub TextBox1_TextChanged(sender As Object, e As EventArgs)
      ' metin değişikliği
      lblInfo1.text=Date.now.Tostring("T") + ": evt [TextChanged] sur [TextBox1]. Texte 1=["+textbox1.Text+"]"
    End Sub

    Sub TextBox2_TextChanged(sender As Object, e As EventArgs)
      ' metin değişikliği
      lblInfo2.text=Date.now.Tostring("T") + ": evt [TextChanged] sur [TextBox2]. Texte 2=["+textbox2.Text+"]"
    End Sub

</script>
<html>
<head>
    <title>asp:textbox</title>
</head>
<body>
    <form runat="server">
        <p>
            Texte 1 :
            <asp:TextBox id="TextBox1" runat="server" AutoPostBack="True" OnTextChanged="TextBox1_TextChanged"></asp:TextBox>
        </p>
        <p>
            Texte 2 :
            <asp:TextBox id="TextBox2" runat="server" OnTextChanged="TextBox2_TextChanged"></asp:TextBox>
        </p>
        <p>
            <asp:Label id="lblInfo1" runat="server"></asp:Label>
        </p>
        <p>
            <asp:Label id="lblInfo2" runat="server"></asp:Label>
        </p>
    </form>
</body>
</html>

Önceki örnekte olduğu gibi, müşterinin talebini kaydetmek için [Page_Init] prosedürünü ekledik.

7.6.2. Testler

WebMatrix uygulamasını [F5] ile başlatıyoruz. Aşağıdaki sayfayı görüyoruz:

Image

Tarayıcı tarafından alınan HTML kodu şöyledir:

<html>
<head>
    <title>asp:textbox</title>
</head>
<body>
    <form name="_ctl0" method="post" action="form4.aspx" id="_ctl0">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" value="dDwtMTY4MDc0MTUxOTs7PoqpeSYSCX7lCiWZvw5p7u+/OrTD" />

<script language="javascript">
<!--
    function __doPostBack(eventTarget, eventArgument) {
        var theform = document._ctl0;
        theform.__EVENTTARGET.value = eventTarget;
        theform.__EVENTARGUMENT.value = eventArgument;
        theform.submit();
    }
// -->
</script>

        <p>
            Texte 1 :
            <input name="TextBox1" type="text" id="TextBox1" onchange="__doPostBack('TextBox1','')" language="javascript" />
        </p>
        <p>
            Texte 2 :
            <input name="TextBox2" type="text" id="TextBox2" />
        </p>
        <p>
            <span id="lblInfo1"></span>

        </p>
        <p>
            <span id="lblInfo2"></span>
        </p>
    </form>
</body>
</html>

Bu kodda sunucu tarafından otomatik olarak oluşturulan birçok öğe bulunmaktadır. Aşağıdaki noktalara dikkat edelim:

  • Üç gizli alan vardır: Daha önce karşılaştığımız [__VIEWSTATE], [__EventTarget] ve [__EventArgument]. Son iki alan, [TextBox1] giriş alanındaki "change" tarayıcı olayını yönetmek için kullanılır
  • <asp:textbox> sunucu etiketleri, giriş alanlarına karşılık gelen HTML <input type="text" ...> etiketlerini oluşturmuştur
  • <asp:textbox id="TextBox1" AutoPostBack="true" ...> sunucu etiketi, [onchange="__doPostBack('TextBox1','')"] özniteliğine sahip bir <input type="text" ...> etiketine dönüşmüştür. Bu öznitelik, [TextBox1] içeriğinde bir değişiklik olması durumunda [_doPostBack(...)] adlı JavaScript işlevinin çalıştırılması gerektiğini belirtir. Bu işlev şöyledir:
<script language="javascript">
<!--
    function __doPostBack(eventTarget, eventArgument) {
        var theform = document._ctl0;
        theform.__EVENTTARGET.value = eventTarget;
        theform.__EVENTARGUMENT.value = eventArgument;
        theform.submit();
    }
// -->
</script>

Yukarıdaki işlev ne işe yarar? [__EventTarget] ve [__EventArgument] adlı iki gizli alana birer değer atar ve ardından formu gönderir. Böylece form sunucuya gönderilir. Bu, [AutoPostBack] işlevinin etkisidir. "change" tarayıcı olayı, "__doPostBack('TextBox1','')" kodunun çalıştırılmasını tetikler. Buradan, gönderilen formda [__EventTarget] gizli alanının değeri 'TextBox1' ve [__EventArgument] gizli alanının değeri ''' olacağı sonucuna varılır. Bu sayede sunucu, POST'i tetikleyen bileşeni tespit edebilecektir.

  • <asp:textbox id="TextBox2"...> sunucu etiketi, [AutoPostBack] özniteliği [true] olarak ayarlanmadığı için standart bir <input type="text" ...> etiketine dönüştü.
  • <form> etiketi, formun [form4.aspx] adresine gönderileceğini belirtir:
    <form name="_ctl0" method="post" action="form4.aspx" id="_ctl0">

İlk testimizi yapalım. İlk giriş alanına bir metin yazalım:

Image

ardından imleci ikinci giriş alanına getirelim. Hemen yeni bir sayfa açılır:

Image

Ne oldu? İmleç ilk giriş alanından çıktığında, tarayıcı bu alanın içeriğinin değişip değişmediğini kontrol etti. Değişmişti. Bu nedenle tarayıcı tarafında, HTML [TextBox1] alanında [change] olayını oluşturdu. Ardından bir JavaScript işlevinin çalıştırıldığını ve formu [form4.aspx] adresine gönderdiğini gördük. Böylece bu sayfa sunucu tarafından yeniden yüklendi. Form tarafından gönderilen değerler, sunucunun da [TextBox1] sunucu etiketinin içeriğinin değiştiğini fark etmesini sağladı. Böylece [TextBox1_Changed] prosedürü sunucu tarafında çalıştırıldı. Bu prosedür, [lblInfo1] etiketine bir mesaj yerleştirdi. Bu yordam tamamlandıktan sonra, [form4.aspx] tarayıcıya gönderildi. Bu nedenle artık [lblInfo1]'te bir metin bulunuyor. Bununla birlikte, [TextBox1] giriş alanında bir şeyin bulunması şaşırtıcı olabilir. Aslında, sunucu tarafında yürütülen hiçbir işlem bu alana bir değer atamaz. Burada ASP.NET web formlarının genel bir mekanizmasıyla karşı karşıyayız: sunucu, formu aldığı haliyle geri gönderir. Bunun için, bileşenlere istemci tarafından kendileri için gönderilen değeri yeniden atar. Bazı bileşenler için istemci herhangi bir değer göndermez. Örneğin, <asp:label> bileşenleri bu duruma örnektir; bunlar <span> etiketlerine dönüştürülür. Hatırlanacağı üzere, formun, istemciye gönderildiğinde formun durumunu temsil eden [__VIEWSTATE] adlı bir gizli alanı vardır. Bu durum, varsa <asp:label> bileşenleri de dahil olmak üzere formdaki tüm bileşenlerin durumlarının toplamıdır. Gizli [__VIEWSTATE] alanı istemci tarayıcısı tarafından gönderildiğinden, sunucu formdaki tüm bileşenlerin önceki durumunu geri yükleyebilir. Artık, POST tarafından değeri değiştirilen bileşenleri güncellemesi yeterlidir.

Şimdi [request.txt] dosyasında tarayıcı tarafından gönderilen isteğe bir göz atalım:

POST /form4.aspx HTTP/1.1
Connection: keep-alive
Keep-Alive: 300
Content-Length: 137
Content-Type: application/x-www-form-urlencoded
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Encoding: gzip,deflate
Accept-Language: en-us,en;q=0.5
Host: localhost
Referer: http://localhost/form4.aspx
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

__EVENTTARGET=TextBox1&__EVENTARGUMENT=&__VIEWSTATE=dDwtMTY4MDc0MTUxOTs7PoqpeSYSCX7lCiWZvw5p7u%2B%2FOrTD&TextBox1=premier+texte&TextBox2=

POST ve gönderilen parametreler açıkça görülüyor. Tarayıcımıza geri dönelim ve ikinci giriş alanına bir metin girelim:

Image

1 numaralı giriş alanına geri dönüp yeni bir metin girelim: bu sefer hiçbir şey olmuyor. Neden? Çünkü [TextBox2] giriş alanı, [AutoPostBack]'ten [true]'e kadar olan özelliğe sahip olmadığından, onun için oluşturulan <input type="text"...> etiketi, kodunda da görüldüğü gibi [Change] olayını desteklemiyor:

            <input name="TextBox2" type="text" id="TextBox2" />

Dolayısıyla, 2 numaralı giriş alanından çıkıldığında herhangi bir olay gerçekleşmez. Şimdi 1 numaralı alana yeni bir metin girelim:

Image

1 numaralı giriş alanından çıkalım. Hemen ardından bu alanda [Change] olayı algılanır ve form sunucuya gönderilir; sunucu da karşılığında şu sayfayı döndürür:

Image

Ne oldu? Öncelikle, tarayıcı formu gönderdi. Bu durum, [request.txt]'te saklanan istemci isteğinde görülebilir:

POST /form4.aspx HTTP/1.1
....
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

__EVENTTARGET=TextBox1&__EVENTARGUMENT=&__VIEWSTATE=dDwtMTY4MDc0MTUxOTt0PDtsPGk8MT47PjtsPHQ8O2w8aTwxPjtpPDU%2BOz47bDx0PHA8cDxsPFRleHQ7PjtsPHByZW1pZXIgdGV4dGU7Pj47Pjs7Pjt0PHA8cDxsPFRleHQ7PjtsPDE4OjQyOjI5OiBldnQgW1RleHRDaGFuZ2VkXSBzdXIgW1RleHRCb3gxXS4gVGV4dGUgMT1bcHJlbWllciB0ZXh0ZV07Pj47Pjs7Pjs%2BPjs%2BPjs%2BxLOermpUUUz5rTAa%2FFsjda6lVmo%3D&TextBox1=troisi%C3%A8me+texte&TextBox2=second+texte

Sunucu, öncelikle istemcinin kendisine gönderdiği gizli alan [__VIEWSTATE] sayesinde bileşenlere önceki değerlerini geri yükler. Gönderilen [TextBox1] ve [TextBox2] alanları sayesinde, [TextBox1] ve [TextBox2] bileşenlerine kendisine gönderilen değerleri atayacaktır. Müşteri, bu mekanizma sayesinde formun gönderildiği haliyle geri alacaktır. Ardından, yine gönderilen [__VIEWSTATE], [TextBox1] ve [TextBox2] alanları sayesinde, sunucu [TextBox1] ve [TextBox2] giriş alanlarının değerlerinin değiştiğini tespit edecektir. Böylece bu iki nesne için [TextChanged] olaylarını oluşturacaktır. [TextBox1_TextChanged] ve [TextBox2_TextChanged] prosedürleri çalıştırılacak ve [labelInfo1] ile [labelInfo2] etiketlerine yeni bir değer atanacaktır. Ardından, bu şekilde değiştirilen [form4.aspx] sayfası müşteriye geri gönderilir.

Şimdi 1 numaralı giriş alanını yeniden değiştiriyoruz:

Image

1 numaralı alandan giriş imlecini çıkardığımızda, tarayıcıda [Change] olayı gerçekleşir. Ardından, daha önce açıklanan olay dizisi (tarayıcıdan sunucuya gönderim, ..., sunucudan yanıtın gönderilmesi) gerçekleşir. Aşağıdaki yanıtı alırız:

Image

Her bir mesajın yanında görüntülenen saat bilgisine bakıldığında, sunucuda yalnızca [TextBox1_Changed] prosedürünün yürütüldüğü görülmektedir. [TextBox2_TextChanged] prosedürü, [TextBox2] değerinin değişmemiş olması nedeniyle yürütülmemiştir. Son olarak, 2 numaralı alana yeni bir metin girelim:

Image

Ardından imleci 1 numaralı alana getirelim ve tekrar 2 numaralı alana geri koyalım. Sayfa değişmiyor. Neden? 1 numaralı alanın değerini değiştirmediğimiz için, bu alandan çıktığımızda [Change] tarayıcı olayı gerçekleşmiyor. Sonuç olarak, form sunucuya gönderilmiyor. Dolayısıyla sayfada hiçbir değişiklik olmuyor. [lblInfo2]'in içeriğinin değişmemesi, POST'in olmadığını bize gösteriyor. Eğer olsaydı, sunucu [TextBox2]'in içeriğinin değiştiğini algılayacak ve bunu [lblInfo2]'te yansıtması gerekecekti.

Bu örnekten çıkarılacak ders, bir [TextBox]'in [AutoPostBack] özelliğini [true]'e atamanın bir anlamı olmadığıdır. Bu, çoğu zaman gereksiz bir istemci-sunucu gidiş-dönüşüne neden olur.

7.6.3. __VIEWSTATE alanının rolü

Sunucunun, oluşturduğu forma sistematik olarak __VIEWSTATE adlı gizli bir alan eklediğini görmüştük. Bu alanın formun durumunu temsil ettiğini ve bu gizli alanın sunucuya geri gönderilmesi durumunda sunucunun formun önceki değerini yeniden oluşturabileceğini belirtmiştik. Bir formun durumu, bileşenlerinin durumlarının toplamıdır. Her bir bileşenin, bileşenin durumunun [__VIEWSATE] adlı gizli alana yerleştirilip yerleştirilmeyeceğini belirten, boole değerine sahip bir [EnableViewState] özelliği vardır. Varsayılan olarak bu özellik [true] değerindedir; bu da bir formdaki tüm bileşenlerin durumunun [__VIEWSTATE]'e yerleştirilmesine neden olur. Bazen bu istenmeyen bir durumdur.

[EnableViewState] özelliğinin rolünü daha iyi anlamak için birkaç deneme yapalım. Her iki giriş alanı için bu özelliği [false] olarak ayarlayalım:

...
            <asp:TextBox id="TextBox1" runat="server" OnTextChanged="TextBox1_TextChanged" AutoPostBack="True" EnableViewState="False"></asp:TextBox>
...
            <asp:TextBox id="TextBox2" runat="server" OnTextChanged="TextBox2_TextChanged" EnableViewState="False"></asp:TextBox>
...

Şimdi uygulamayı çalıştıralım ve 2 numaralı alana geçmeden önce 1 numaralı alana ilk metni girelim. Ardından sunucuya bir POST isteği gönderilir ve şu yanıt alınır:

Image

2 numaralı alana bir metin yazalım, 1 numaralı alandaki metni değiştirelim ve ardından tekrar 2 numaralı alana dönelim (bu sırayla). Sunucuya yeni bir POST isteği gönderilir ve şu yanıtı alırız:

Image

Şu an için her şey eskisi gibi. Şimdi 1 numaralı alanın içeriğini değiştirelim ve ardından 2 numaralı alana geçelim. Yeni bir POST isteği gönderilir. Sunucudan gelen yanıt şöyledir:

Image

Bu sefer bir değişiklik var. [lblInfo2]'in saati değiştirildiği için sunucu, 2 numaralı alanda bir [TextChanged] olayı algıladı. Oysa herhangi bir değişiklik olmamıştı. Bunun nedeni, [TextBox2]'in [EnableViewState=false] özelliğidir. Bu özellik, sunucunun formdaki [__VIEWSTATE] alanına [TextBox2]'in önceki durumunu kaydetmemesine neden olur. Bu, önceki durum olarak boş bir dize atanması anlamına gelir. [TextBox1]'in içeriğindeki değişiklik nedeniyle POST oluştuğunda, sunucu [TextBox2]'in o andaki değeri olan [deux]'i önceki değeriyle (boş dize) karşılaştırdı. Bunun üzerine, [TextBox2]'in değerinin değiştiği sonucuna varmış ve [TextBox2] için [TextChanged] olayını oluşturmuştur. Bu işleyişi, [TextBox2]'e boş dizeyi girerek doğrulayabiliriz. Az önce açıklananlara göre, sunucu [TextBox2] için [TextChanged] olayını oluşturmamalıdır. Deneyelim:

Image

Aynen böyle oldu. [lblInfo2]'in saati ve içeriği, [TextBox2_TextChanged] prosedürünün yürütülmediğini gösteriyor. Bunu anladıktan sonra, formun dört bileşeninin [EnableViewState] özelliğini inceleyelim:

TextBox1
sunucunun bu bileşenin durumunun değişip değişmediğini bilmesi için bu bileşenin durumunu korumak istiyoruz
TextBox2
aynı şekilde
lblInfo1
Bu bileşenin durumunu korumak istemiyoruz. Metnin her yeni POST'te yeniden hesaplanmasını istiyoruz. Yeniden hesaplanmazsa, boş kalmalıdır. Tüm bunlar [EnableViewState=false] ile başarıyla elde edilir
lblInfo2 
aynı şekilde

Tanıtım sayfamız şu şekilde oluyor:

...
            <asp:TextBox id="TextBox1" runat="server" OnTextChanged="TextBox1_TextChanged" AutoPostBack="True"></asp:TextBox>
...
            <asp:TextBox id="TextBox2" runat="server" OnTextChanged="TextBox2_TextChanged"></asp:TextBox>
....
            <asp:Label id="lblInfo1" runat="server" enableviewstate="False"></asp:Label>
...
            <asp:Label id="lblInfo2" runat="server" enableviewstate="False"></asp:Label>
...

Daha önce yaptığımız test serisini tekrar yapalım. Şu ekranı elde ettiğimiz yerde

version 1

Image

şimdi şunu görüyoruz:

version 2

Image

Bu adımda, alan 2’nin içeriğini değiştirmeden alan 1’in içeriğini değiştiriyorduk; bu da [TextBox2_TextChanged] prosedürünün sunucu tarafında yürütülmemesine neden oluyordu. Dolayısıyla, [lblInfo2] alanı yeni bir değer almıyordu. Bu nedenle, önceki değeriyle görüntüleniyor. [EnableViewState=true] (Sürüm 1) versiyonunda bu önceki değer, girilen değerdi. [EnableViewState=false] (Sürüm 2) versiyonunda ise bu önceki değer boş bir dizedir.

Bazen bileşenlerin önceki durumunu korumak gereksiz olabilir. Her biri için [EnableViewState=false] ayarını yapmak yerine, sayfanın durumunu korumaması gerektiğini belirtebiliriz. Bu, sunum kodundaki [Page] yönergesinde yapılır:

<%@ Page Language="VB" EnableViewState="False" %>

Bu durumda, [EnableViewState] özelliğinin değeri ne olursa olsun, bir bileşenin durumu [__VIEWSTATE] gizli alanına kaydedilmez. Böylece, sanki önceki durumu boş bir dizeymiş gibi davranılır.

Şimdi, diğer mekanizmaları ortaya çıkarmak için [curl] istemcisini kullanalım. Öncelikle [http://localhost/form4.aspx] URL’sini çağırıyoruz:

dos>curl --include --url http://localhost/form4.aspx

HTTP/1.1 200 OK
Server: Microsoft ASP.NET Web Matrix Server/0.6.0.0
Date: Sun, 04 Apr 2004 17:51:14 GMT
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 1077
Connection: Close


<html>
<head>
    <title>asp:textbox</title>
</head>
<body>
    <form name="_ctl0" method="post" action="form4.aspx" id="_ctl0">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" value="dDwtMTY4MDc0MTUxOTs7PoqpeSYSCX7lCiWZvw5p7u+/OrTD" />

<script language="javascript">
<!--
    function __doPostBack(eventTarget, eventArgument) {
        var theform = document._ctl0;
        theform.__EVENTTARGET.value = eventTarget;
        theform.__EVENTARGUMENT.value = eventArgument;
        theform.submit();
    }
// -->
</script>

        <p>
            Texte 1 :
            <input name="TextBox1" type="text" id="TextBox1" onchange="__doPostBack('TextBox1','')" language="javascript" />
        </p>
        <p>
            Texte 2 :
            <input name="TextBox2" type="text" id="TextBox2" />
        </p>
        <p>
            <span id="lblInfo1"></span>
        </p>
        <p>
            <span id="lblInfo2"></span>
        </p>
    </form>
</body>
</html>

Sunucudan HTML kodunu alıyoruz ([form4.aspx]'ten). Bu kod, tarayıcının aldığı koddan farklı değildir. Burada, tarayıcının formu gönderirken yaptığı isteği hatırlayalım:

POST /form4.aspx HTTP/1.1
Connection: keep-alive
...
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316

__EVENTTARGET=TextBox1&__EVENTARGUMENT=&__VIEWSTATE=dDwtMTY4MDc0MTUxOTs7PoqpeSYSCX7lCiWZvw5p7u%2B%2FOrTD&TextBox1=premier+texte&TextBox2=

Aynı POST işlemini, [__VIEWSTATE] alanını göndermeden yapalım:

dos>curl --include --url http://localhost/form4.aspx --data __EVENTTARGET=TextBox1 --data __EVENTARGUMENT= --data TextBox1=ilk+metin --data TextBox2=

...................
        <p>
            Texte 1 :
            <input name="TextBox1" type="text" value="premier texte" id="TextBox1" onchange="__doPostBack('TextBox1','')" language="javascript" />
        </p>
        <p>
            Texte 2 :
            <input name="TextBox2" type="text" id="TextBox2" />
        </p>
        <p>
            <span id="lblInfo1">19:57:48: evt [TextChanged] sur [TextBox1]. Texte 1=[premier texte]</span>
        </p>
        <p>
            <span id="lblInfo2"></span>
        </p>
..............

Aşağıdaki noktalara dikkat edilmelidir:

  • Sunucu, [lblInfo1] metnini oluşturduğu için [TextBox1] üzerinde bir [TextChanged] olayı algılamıştır. [__VIEWSTATE]'in olmaması onu engellemedi. Bu değerin yokluğunda, bir giriş alanının önceki değerinin boş bir dize olduğunu varsaymaktadır.
  • [TextBox1] için gönderilen metni, [TextBox1] etiketinin [value] özniteliğine geri yerleştirebildi; böylece [TextBox1] alanı girilen değerle yeniden göründü. Bunun için [__VIEWSTATE]'e ihtiyacı yok, sadece [TextBox1] için gönderilen değere ihtiyacı var.

Şimdi, hiçbir şeyi değiştirmeden aynı sorguyu tekrar yapalım. Aşağıdaki yeni yanıtı alıyoruz:

dos>curl --include --url http://localhost/form4.aspx --data __EVENTTARGET=TextBox1 --data __EVENTARGUMENT= --data TextBox1=ilk+metin --data TextBox2=


        <p>
            Texte 1 :
            <input name="TextBox1" type="text" value="premier texte" id="TextBox1" onchange="__doPostBack('TextBox1','')" language="javascript" />
        </p>
        <p>
            Texte 2 :
            <input name="TextBox2" type="text" id="TextBox2" />
        </p>
        <p>
            <span id="lblInfo1">20:05:47: evt [TextChanged] sur [TextBox1]. Texte 1=[premier texte]</span>
        </p>
        <p>
            <span id="lblInfo2"></span>
        </p>

[__VIEWSTATE] bulunmadığından, sunucu [TextBox1] alanının değerinin değişmediğini algılayamadı. Bu durumda, önceki değerin boş bir dizeymiş gibi davranır. Bu nedenle burada [TextBox1] üzerinde [TextChanged] olayını oluşturdu. Aynı isteği, bu sefer [TextBox1] alanı boş ve [TextBox2] alanı boş olmayan şekilde tekrar çalıştıralım:

dos>curl --include --url http://localhost/form4.aspx --data __EVENTTARGET=TextBox1 --data __EVENTARGUMENT= --data TextBox2=ikinci+metin --data TextBox1=
......
        <p>
            Texte 1 :
            <input name="TextBox1" type="text" id="TextBox1" onchange="__doPostBack('TextBox1','')" language="javascript" />
        </p>
        <p>
            Texte 2 :
            <input name="TextBox2" type="text" value="second texte" id="TextBox2" />
        </p>
        <p>
            <span id="lblInfo1"></span>
        </p>
        <p>
            <span id="lblInfo2">20:11:54: evt [TextChanged] sur [TextBox2]. Texte 2=[second texte]</span>
        </p>
......

[__VIEWSTATE] bulunmadığından, [TextBox1]'in önceki değeri boş dize olarak kabul edildi. [TextBox1]'in kaydedilen değeri de boş dize olduğundan, [TextBox1] üzerindeki [TextChanged] olayı oluşturulmadı. [TextBox1_TextChanged] prosedürü yürütülmedi ve bu nedenle [lblInfo1] alanı yeni bir değer almadı. Bu durumda bileşenin eski değerini koruduğu bilinmektedir. Ancak burada durum böyle değildir; [lblInfo1] önceki değerini kaybetmiştir. Bunun nedeni, bu değerin [__VIEWSTATE]'te aranmasıdır. Bu alan mevcut olmadığından, [lblInfo1]'e boş bir dize atanmıştır. [TextBox2] için sunucu, gönderilen değeri olan [second texte]'i önceki değeriyle karşılaştırmıştır. [__VIEWSTATE] mevcut olmadığından, bu önceki değer boş dizgiye eşittir. [TextBox2]'in gönderilen değeri boş dizeden farklı olduğundan, [TextBox2] üzerinde [TextChanged] olayı oluşturulmuştur. [TextBox2_TextChanged] prosedürü yürütüldü ve [lblInfo2] alanına yeni bir değer atandı.

[__EVENTTARGET] ve [__EVENTARGUMENT] parametrelerinin gerçekten gerekli olup olmadığı sorgulanabilir. Bu parametreler gönderilmezse, sunucu [submit] olayının hangi olay tarafından tetiklendiğini bilemeyecektir. Şunu deneyelim:

dos>curl --include --url http://localhost/form4.aspx --data TextBox2=ikinci+metin --data TextBox1=ilk+metin
..............................
        <p>
            Texte 1 :
            <input name="TextBox1" type="text" id="TextBox1" onchange="__doPostBack('TextBox1','')" language="javascript" />
        </p>
        <p>
            Texte 2 :
            <input name="TextBox2" type="text" id="TextBox2" />
        </p>
        <p>
            <span id="lblInfo1"></span>
        </p>
        <p>
            <span id="lblInfo2"></span>
        </p>
    </form>
.....................

Görüldüğü üzere, hiçbir [TextChanged] olayı işlenmemiştir. Ayrıca, gönderilen [TextBox1] ve [TextBox2] alanları, gönderilen değerlerini geri bulamamaktadır. Aslında her şey sanki bir GET işlemi yapılmış gibi gerçekleşiyor. Gönderilen alanlar arasında [__EVENTTARGET] alanı varsa, bu alanda değer olmasa bile her şey normale dönüyor:

dos>curl --include --url http://localhost/form4.aspx --data __EVENTTARGET= --data TextBox2=ikinci+metin --data TextBox1=ilk+metin
.......
        <p>
            Texte 1 :
            <input name="TextBox1" type="text" value="premier texte" id="TextBox1" onchange="__doPostBack('TextBox1','')" language="javascript" />
        </p>
        <p>
            Texte 2 :
            <input name="TextBox2" type="text" value="second texte" id="TextBox2" />
        </p>
        <p>
            <span id="lblInfo1">20:34:14: evt [TextChanged] sur [TextBox1]. Texte 1=[premier texte]</span>
        </p>
        <p>
            <span id="lblInfo2">20:34:14: evt [TextChanged] sur [TextBox2]. Texte 2=[second texte]</span>
        </p>
........

7.6.4. TextBox bileşeninin diğer özellikleri

[TextBox] sunucu bileşeni ayrıca, sırasıyla korumalı giriş alanı ve çok satırlı giriş alanına karşılık gelen <input type="password"..> ve <texarea>..</textarea> etiketlerini oluşturmaya da olanak tanır. Bu etiketler sırasıyla korumalı bir giriş alanı ve çok satırlı bir giriş alanına karşılık gelir. Bu oluşturma işlemi, [TextBox] bileşeninin [TextMode] özelliği tarafından kontrol edilir. Bu özelliğin üç olası değeri vardır:

değer
Oluşturulan HTML etiketi
SingleLine
<input type="text" ...>
MultiLine
<textarea>...</textarea>
Password
<input type="password ...>

Aşağıdaki [form5.aspx] örneğiyle bu özelliklerin kullanımını inceleyeceğiz:

Image

no
ad
tür
özellikler
rol
1
btnAjouter
Düğme
 
[submit] düğmesi - [TextBox1]'in içeriğini [TextBox2]'in içeriğine eklemek için kullanılır
2
TextBox1
TextBox
TextMode=Password
Text=
korumalı giriş alanı
3
TextBox2
TextBox
TextMode=Çok satırlı
Text=
[TextBox1]'te yapılan girişleri birleştirir

Sayfanın [EnableViewState] özelliği, [false] olarak ayarlanır. Sunucu tarafında, [btnAjouter] düğmesine tıklama olayını yönetiyoruz:

Sub btnAjouter_Click(sender As Object, e As EventArgs)
  ' [textBox1] dosyasının içeriği, [TextBox2] dosyasının içeriğine eklenir
  textbox2.text=textbox2.text + textbox1.text+controlchars.crlf
End Sub

Bu kodu anlamak için, bir formdaki POST olayının işlenme şeklini hatırlamak gerekir. Öncelikle [Page_Init] ve [Page_Load] prosedürleri yürütülür. Ardından önbelleğe alınmış tüm olay prosedürleri gelir. Son olarak, [POST]'i tetikleyen olayı yöneten prosedür, yani bu durumda [btnAjouter_Click] prosedürü yürütülür. Olay işleyicileri yürütüldüğünde, POST'te bir değeri olan sayfanın tüm bileşenleri bu değeri alır. Diğer bileşenler ise, [EnableViewState] özelliği [true] değerindeyse önceki değerlerine, [EnableViewState] özelliği [false] değerindeyse tasarım değerlerine geri döner. Burada, [TextBox1] ve [TextBox2] alanlarının değerleri, müşteri tarafından girilen POST değerinin bir parçası olacaktır. Ayrıca önceki kodda, [textbox1.text]'in değeri müşteri tarafından gönderilen değer olacak; aynı durum [textbox2.text] için de geçerlidir. [btnAjouter_Click] prosedürü, [TextBox2] alanına, [TextBox2] için gönderilen değere, [TextBox1] için gönderilen değerin eklenmiş hali ve [ControlChars.CrLf]'e eklenir. Bu ad alanını içe aktarmanıza gerek yoktur; web sunucusu bunu varsayılan olarak içe aktarır.

[form5.aspx]'in nihai kodu şöyledir:

<%@ Page Language="VB" EnableViewState="False" %>
<script runat="server">

    Sub btnAjouter_Click(sender As Object, e As EventArgs)
      ' [textBox1] dosyasının içeriği, [TextBox2] dosyasının içeriğine eklenir
      textbox2.text+=textbox1.text+controlchars.crlf
    End Sub

</script>
<html>
<head>
</head>
<body>
    <form runat="server">
        <p>
            <asp:Button id="btnAjouter" onclick="btnAjouter_Click" runat="server" Text="Ajouter" EnableViewState="False"></asp:Button>
            <asp:TextBox id="TextBox1" runat="server" TextMode="Password" Width="353px" EnableViewState="False"></asp:TextBox>
        </p>
        <p>
            <asp:TextBox id="TextBox2" runat="server" TextMode="MultiLine" Width="419px" Height="121px" EnableViewState="False"></asp:TextBox>
        </p>
    </form>
</body>
</html>

Biraz daha yukarıda, bir çalıştırmanın ekran görüntüsü verilmiştir.

7.7. DropDownList bileşeni

<asp:DropDownList> etiketi, bir sayfanın sunum koduna bir açılır liste eklemeye olanak tanır. Aşağıdaki sunumu elde etmek için [form6.aspx] adlı bir sayfa oluşturuyoruz:

Image

no
ad
tür
özellikler
rol
1
DropDownList1
DropDownList
AutoPostback=true
EnableViewState=true
açılır liste
2
lblInfo
Etiket
EnableViewState=false
bilgi mesajı

Oluşturulan sunum kodu şöyledir:

Page Language="VB" %>
<script runat="server">

</script>
<html>
<head>
</head>
<body>
    <form runat="server">
        <p>
            <asp:DropDownList id="DropDownList1" runat="server" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" AutoPostBack="True"></asp:DropDownList>
        </p>
        <p>
            <asp:Label id="lblInfo" runat="server" enableviewstate="False"></asp:Label>
        </p>
    </form>
</body>
</html>

Şu anda açılır liste hiçbir öğe içermiyor. Bunu [Page_Load] prosedüründe dolduracağız. Bunun için [DropDownList] sınıfının bazı özelliklerini ve yöntemlerini bilmemiz gerekiyor:

Items
Açılır listenin öğelerini içeren [ListItemCollection] türünde bir koleksiyon. Bu koleksiyonun elemanları [ListItem] türündedir.
Items.Count
[Items] koleksiyonundaki öğe sayısı
Items(i)
listenin i numaralı öğesi - türü [ListItem]
Items.Add
koleksyona yeni bir öğe eklemek için [ListItem] [Items]
Items.Clear
[Items] koleksiyonundaki tüm öğeleri silmek için
Items.RemoveAt(i)
[Items] koleksiyonundan i numaralı öğeyi silmek için
SelectedItem
[Items] koleksiyonundaki, [ListItem] numaralı ilk öğe, [Selected] özelliğinin değeri "true" olan
SelectedIndex
[Items] koleksiyonundaki [SelectedItem] öğesinin numarası

[DropDownList] sınıfına ait [Items] koleksiyonundaki öğeler, [ListItem] türündedir. Her bir [ListItem] öğesi, bir HTML <option> etiketini oluşturur:

<option value="V" [selected="selected"]>T</option>

[ListItem] sınıfının bazı özelliklerini ve yöntemlerini açıklıyoruz:

ListItem(String texte, String value)
yapıcı - [ListItem] öğesini, [texte] ve [value] özellikleriyle oluşturur. Bir ListItem(T,V) öğesi, HTML <option value="V">T</option> etiketini oluşturur. Dolayısıyla, [ListITem] sınıfı, bir HTML listesinin öğelerini tanımlamaya olanak tanır.
Selected
boole listesindeki öğeleri tanımlamaya olanak tanır. Değer "true" ise, HTML listesindeki ilgili seçeneğin [selected="selected"] özniteliği olacaktır. Bu öznitelik, tarayıcıya ilgili öğenin HTML listesinde seçili olarak görünmesi gerektiğini bildirir
Text
HTML seçeneğindeki T metni <option value="V" [selected="selected"]>T</option>
Value
HTML seçeneğinin [Value] özniteliğinin V değeri <option value="V" [selected="selected"]>T</option>

Sayfanın [Page_Load] prosedürüne, [DropDownList1] açılır listesini dolduracak kodu yazmak için yeterli bilgiye sahibiz:

    Sub Page_Load(sender As Object, e As EventArgs)
        ' eğer ilk kez çağrılıyorsa, açılır menü doldurulur
        if not IsPostBack then
          dim valeurs() as String = {"1","2","3","4"}
            dim textes() as  String = {"un","deux","trois","quatre"}

            dim i as integer
            for i=0 to valeurs.length-1
                DropDownList1.Items.Add(new ListItem(textes(i),valeurs(i)))
            next
        end if
    end sub

[DropDownList1] bileşeni bu şekilde başlatıldığında, HTML çevirisi şu şekilde olacaktır:

<select name="DropDownList1" id="DropDownList1" onchange="__doPostBack('DropDownList1','')" language="javascript">

    <option value="1">un</option>
    <option value="2">deux</option>
    <option value="3">trois</option>
    <option value="4">quatre</option>

</select>

[Page_Load] prosedürünün, [form6.aspx] sayfası her çalıştırıldığında yürütüldüğünü biliyoruz. Bu sayfa ilk olarak GET tarafından çağrılır, ardından kullanıcı açılır listeden yeni bir öğe seçtiğinde her seferinde POST tarafından çağrılır. [Page_Load]'teki bu listeyi doldurma kodu her seferinde çalıştırılmalı mı? Cevap, [DropDownList1] bileşeninin [EnableViewState] özniteliğine bağlıdır. Bu öznitelik "true" ise, [DropDownList1] bileşeninin durumunun, gizli alan [__VIEWSTATE]'te istekler boyunca korunacağı bilinir. Bu durum iki şeyi içerir:

  • açılır listedeki tüm değerlerin listesi
  • bu listeden seçilen öğenin değeri

Bu durumda, listeye eklenecek değerleri yeniden hesaplamak zorunda kalmamak için [DropDownList1] bileşeninin [EnableViewState] özelliğini [true] olarak ayarlamak cazip gelebilir. Ancak sorun şu ki, [form6.aspx] sayfası her çağrıldığında [Page_Load] prosedürü de çalıştırıldığından, bu değerler yine de hesaplanacaktır. [form6.aspx]'in bir örneği olduğu [Page] nesnesi, boole değerine sahip bir [IsPostBack] özniteliğine sahiptir. Bu öznitelik "true" ise, bu, sayfanın bir POST tarafından çağrıldığı anlamına gelir. Değer "yanlış" ise, bu, sayfanın bir GET tarafından çağrıldığı anlamına gelir. İstemci-sunucu arasında gidip gelen sistemimizde, istemci sunucuya her zaman aynı [form6.aspx] sayfasını ister. İlk seferinde sayfayı GET ile ister, sonraki seferlerde ise POST ile ister. Bundan, [IsPostBack] özelliğinin, istemcinin ilk GET çağrısını tespit etmek için kullanılabileceği sonucuna varılır. Açılır listenin değerleri yalnızca bu ilk çağrı sırasında oluşturulur. Sonraki isteklerde bu değerler, [VIEWSTATE] mekanizması tarafından oluşturulacaktır. Diğer durumlarda, bir listenin içeriği istekten isteğe değişebilir ve bu durumda her istekte yeniden hesaplanması gerekir. Bu durumda, listenin [EnableViewState] özniteliği, [false] olarak ayarlanır; böylece, listede daha önce seçilen öğeleri bilmek gerekmedikçe, liste içeriğinin gereksiz yere iki kez hesaplanması önlenir; çünkü bu bilgi [VIEWSTATE]'te saklanır.

[DropDownList1] listesinin [AutoPostBack] özniteliği "true" olarak ayarlandı. Bu, tarayıcının açılır listede "seçili öğenin değişmesi" olayını algıladığı anda formu göndereceği anlamına gelir. Sunucu da [VIEWSTATE] ve gönderilen değerler sayesinde, [DropDownList1] bileşeninde seçili öğenin değiştiğini algılayacaktır. Ardından bu bileşende [SelectedIndexChanged] olayını tetikleyecektir. Bunu aşağıdaki prosedürle işleyeceğiz:

    Sub DropDownList1_SelectedIndexChanged(sender As Object, e As EventArgs)
      ' seçim değiştirilir
      lblInfo.text="Elément sélectionné : texte="+dropdownlist1.selecteditem.text+ _
        " valeur=" + dropdownlist1.selecteditem.value + _
        " index="+ dropdownlist1.selectedindex.tostring
    End Sub

Bu prosedür yürütüldüğünde, [DropDownList1] nesnesi, [VIEWSTATE] sayesinde [ListItem] türündeki öğelerini geri kazanmıştır. Ayrıca, [ListItem] türündeki öğelerden birinin [Selected] özniteliği "true" değerindedir; bu, tarayıcı tarafından gönderilen değerdir. Bu öğeye çeşitli yollarla erişilebilir:

DropDownList1.SelectedItem
, listede [Selected] özniteliği "true" olarak ayarlanmış ilk [ListItem] öğesidir
DropDownList1.SelectedItem.Text
kullanıcı tarafından seçilen <option value="...">metin</option> öğesinin HTML etiketindeki [texte] kısmına karşılık gelir
DropDownList1.SelectedItem.Value
kullanıcı tarafından seçilen <option value="...">metin</option> öğesinin HTML etiketindeki [value] kısmına karşılık gelir
DropdDownList1.SelectedIndex
[DropDownList1.Items] koleksiyonundaki, [ListItem] ögelerinin [Selected] özniteliği "true" olarak ayarlanmış olan ilk öğenin numarası

[form6.aspx]'in nihai kodu şöyledir:

<%@ Page Language="VB" %>
<script runat="server">

    Sub Page_Load(sender As Object, e As EventArgs)
        ' İlk kez çağrılıyorsa kombinasyon doldurulur
        if not IsPostBack then
          dim valeurs() as String = {"1","2","3","4"}
            dim textes() as  String = {"un","deux","trois","quatre"}

            dim i as integer
            for i=0 to valeurs.length-1
                DropDownList1.Items.Add(new ListItem(textes(i),valeurs(i)))
            next
        end if
    end sub

    Sub DropDownList1_SelectedIndexChanged(sender As Object, e As EventArgs)
      ' seçim değişikliği
      lblInfo.text="Elément sélectionné : texte="+dropdownlist1.selecteditem.text+ _
        " valeur=" + dropdownlist1.selecteditem.value + _
        " index="+ dropdownlist1.selectedindex.tostring
    End Sub

</script>
<html>
<head>
</head>
<body>
    <form runat="server">
        <p>
            <asp:DropDownList id="DropDownList1" runat="server" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" AutoPostBack="True"></asp:DropDownList>
        </p>
        <p>
            <asp:Label id="lblInfo" runat="server" enableviewstate="False"></asp:Label>
        </p>
    </form>
</body>
</html>

7.8. ListBox bileşeni

<asp:ListBox> etiketi, bir sayfanın sunum koduna bir liste eklemeye olanak tanır. Aşağıdaki sunumu elde etmek için [form7.aspx]'i oluşturuyoruz:

Image

no
ad
tür
özellikler
rol
1
txtSaisie
TextBox
EnableViewState=false
giriş alanı
2
btnAjouter
Düğme
 
[submit] düğmesi, txtSaisie'in içeriği boş değilse, bu içeriği Liste 1'e aktarır.
3
ListBox1
ListBox
EnableViewState=true
SelectionMode=Single
tek seçimli değer listesi
4
ListBox2
ListBox
EnableViewState=true
Seçim Modu=Çoklu
çoklu seçim değer listesi
5
btn1vers2
Düğme
 
[liste 1]'ten seçilen öğeyi [liste 2]'e aktaran [submit] düğmesi
6
btn2vers1
Düğme
 
[submit] düğmesi, [liste 2]'ten seçilen öğeleri [liste 1]'e aktarır

Oluşturulan sunum kodu şöyledir:

<%@ Page Language="VB" %>
<script runat="server">
</script>
<html>
<head>
</head>
<body>
    <form runat="server">
        <p>
            Tapez un texte pour l'inclure dans Liste 1 :
            <asp:TextBox id="txtSaisie" runat="server" EnableViewState="False"></asp:TextBox>
        </p>
        <p>
            <asp:Button id="btnAjouter" onclick="btnAjouter_Click" runat="server" Text="Ajouter"></asp:Button>
        </p>
        <p>
            <table>
                <tbody>
                    <tr>
                        <td>
                            <p align="center">
                                Liste 1
                            </p>
                        </td>
                        <td>
                        </td>
                        <td>
                            <p align="center">
                                Liste 2
                            </p>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <asp:ListBox id="ListBox1" runat="server"></asp:ListBox>
                        </td>
                        <td>
                            <p>
                                <asp:Button id="btn1vers2" onclick="btn1vers2_Click" runat="server" Text="-->"></asp:Button>
                            </p>
                            <p>
                                <asp:Button id="btn2vers1" onclick="btn2vers1_Click" runat="server" Text="<--"></asp:Button>
                            </p>
                        </td>
                        <td>
                            <p>
                                <asp:ListBox id="ListBox2" runat="server" SelectionMode="Multiple"></asp:ListBox>
                            </p>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <p align="center">
                                <asp:Button id="btnRaz1" onclick="btnRaz1_Click" runat="server" Text="Effacer"></asp:Button>
                            </p>
                        </td>
                        <td>
                        </td>
                        <td>
                            <p align="center">
                                <asp:Button id="btnRaz2" onclick="btnRaz2_Click" runat="server" Text="Effacer"></asp:Button>
                            </p>
                        </td>
                    </tr>
                </tbody>
            </table>
        </p>
    </form>
</body>
</html>

[ListBox] sınıfı, daha önce incelenen [DropDownList] sınıfıyla aynı olan [ListControl] sınıfından türetilmiştir. Burada, [DropDownList] için incelenen tüm özellikler ve yöntemler de bulunur; çünkü bunlar aslında [ListControl] sınıfına aitti. Yeni bir özellik ortaya çıkmaktadır:

SelectionMode
bu özellik, bileşenden oluşturulacak HTML <select> listesinin seçim modunu belirler. SelectionMode=Single ise, yalnızca tek bir öğe seçilebilir. SelectionMode=Multiple ise, birden fazla öğe seçilebilir. Bunun için, [multiple="multiple"] özniteliği, HTML listesinin <select> etiketinde oluşturulacaktır.

Olayları işleyelim. [Ajouter] düğmesine tıklama, aşağıdaki [btnAjouter_Click] yordamı tarafından işlenecektir:

    Sub btnAjouter_Click(sender As Object, e As EventArgs)
      ' Liste 1'e ekleme
      dim texte as string=txtSaisie.text.trim
      if texte<> "" then ListBox1.Items.Add(New ListItem(texte))
      ' txtSaisie listesini sıfırla
      txtSaisie.text=""
    End Sub

[txtSaisie]'e girilen metin boş veya beyaz bir dize değilse, [ListBox1] listesine yeni bir öğe eklenir. [ListItem] türünde bir öğe eklememiz gerektiğini biliyoruz. Daha önce, benzer bir iş yapmak için [ListItem(T as String, V as String)] oluşturucusunu kullanmıştık. Böyle bir öğe, HTML [<option value="V">T</option>] etiketini oluşturur. Burada, [ListItem(T as String)] oluşturucusunu kullanıyoruz; bu, HTML, [<option value="T">T</option>] ve c.a.d etiketlerini oluşturur. Seçeneğin [T] metni, seçeneğin değerini oluşturmak için alınır. [txtSaisie] içeriği [ListBox1] listesine eklendikten sonra, [txTSaisie] alanı boşaltılır.

[Effacer] düğmelerine yapılan tıklamalar aşağıdaki prosedürlerle işlenecektir:

    Sub btnRaz1_Click(sender As Object, e As EventArgs)
      ' Liste 1'i sıfırla
      ListBox1.Items.Clear
    End Sub

    Sub btnRaz2_Click(sender As Object, e As EventArgs)
      ' liste 2'yi sıfırla
      ListBox2.Items.Clear
    End Sub

Listeler arası geçiş düğmelerine yapılan tıklamalar ise aşağıdaki prosedürlerle işlenir:

    Sub btn1vers2_Click(sender As Object, e As EventArgs)
      ' seçilen öğenin liste 1'den liste 2'ye aktarılması
      transfert(ListBox1,ListBox2)
    End Sub

    Sub btn2vers1_Click(sender As Object, e As EventArgs)
      ' Liste 2'de seçilen öğenin Liste 1'e aktarılması
      transfert(ListBox2,ListBox1)
    End Sub

    sub transfert(l1 as listbox, l2 as listbox)
      ' l1'de seçilen öğelerin l2'ye aktarılması
       ' Yapılması gereken bir şey mi var?
      if l1.selectedindex=-1 then return
      dim i as integer
      ' sonundan başlıyoruz
      for i=l1.items.count-1 to 0 step -1
        ' seçildi mi?
        if l1.items(i).selected then
            ' artık seçili değil
            l1.items(i).selected=false
          ' l2'ye aktarım
          l2.items.add(l1.items(i))
          ' l1'den silme
          l1.items.removeAt(i)
        end if
      next
    end sub

Her iki düğme de aynı işlevi gördüğü için (bir listeden diğerine öğeleri aktarmak), iki parametreli tek bir aktarım prosedürüne indirgenebilir:

  • [ListBox] türündeki l1, yani kaynak liste
  • l2, [ListBox] türünde ve hedef listedir

Öncelikle, l1 listesinde en az bir öğenin seçili olup olmadığı kontrol edilir; aksi takdirde yapılacak bir işlem yoktur. Bunun için, listede seçili ilk öğenin numarasını temsil eden [l1.selectedindex] özelliğini inceleriz. Hiçbir öğe yoksa, değeri -1'dir. l1'de en az bir öğe seçiliyse, l2'ye aktarım gerçekleştirilir. Bunun için l1'deki tüm öğe listesi taranır ve her bir öğe için [selected] özniteliğinin "true" olup olmadığı kontrol edilir. Eğer öyleyse, ilgili öğenin [selected] özniteliği [false] olarak güncellenir, ardından l2 listesine kopyalanır ve son olarak l1 listesinden silinir. Bu silme işlemi, l1 listesindeki öğelerin yeniden numaralandırılmasına neden olur. Bu nedenle l1 listesindeki öğeler ters yönde taranır. Eğer liste normal yönde taranır ve 10 numaralı öğe silinirse, 11 numaralı öğe 10 numara olur ve 12 numaralı öğe de 11 numara olur. 10 numaralı öğeyi işledikten sonra, normal yöndeki döngümüz 11 numaralı öğeyi işleyecektir; az önce açıkladığımız gibi bu, eski 12 numaralı öğedir. Eskiden 11 numara olan ve şimdi 10 numara olan öğe ise gözden kaçar. l1 listesinin öğelerini ters yönde tarayarak bu sorunu önleriz.

7.9. CheckBox ve RadioButton bileşenleri

<asp:RadioButton> ve <asp:CheckBox> etiketleri, bir sayfanın sunum koduna sırasıyla bir radyo düğmesi ve bir onay kutusu eklemeye olanak tanır. Aşağıdaki sunumu elde etmek için [form8.aspx] adlı bir sayfa oluşturuyoruz:

Image

no
ad
tür
özellikler
rol
1
RadioButton1
RadioButton2
RadioButton3
RadioButton
RadioButton1.Checked=true
RadioButton1.Text=1
RadioButton2.Checked=false
RadioButton2.Text=2
RadioButton3.Checked=false
RadioButton3.Text=3
3 düğme için: GroupName=radio
radyo düğmeleri
2
CheckBoxA
CheckBoxB
CheckBoxC
CheckBox
Hepsi için Checked=false
CheckBoxA.Text=A
CheckBoxB.Text=B CheckBoxC.Text=C
onay kutuları
3
btnEnvoyer
Düğme
 
düğme [submit]
4
lstInfos
ListBox
 
bilgi listesi

Tarayıcının bu üç radyo düğmesini birbirini dışlayan düğmeler olarak işlemesi için, bunları bir radyo düğmesi grubu içinde bir araya getirmek gerekir. Bu, [RadioButton] sınıfının [GroupName] özniteliği kullanılarak yapılır. Bu uygulamada sayfanın durumu korunmasına gerek yoktur. Bu nedenle sayfaya [EnableViewState="false"] özniteliğini ekliyoruz. Görüntüleme kodu şöyledir:

<html>
<head>
</head>
<body>
    <form id="frmControls" runat="server">
        <h3>Cases à cocher 
        </h3>
        <p>
            <asp:RadioButton id="RadioButton1" runat="server" Checked="True" EnableViewState="False" GroupName="radio" Text="1"></asp:RadioButton>
            <asp:RadioButton id="RadioButton2" runat="server" EnableViewState="False" GroupName="radio" Text="2"></asp:RadioButton>
            &nbsp;<asp:RadioButton id="RadioButton3" runat="server" EnableViewState="False" GroupName="radio" Text="3"></asp:RadioButton>
        </p>
        <p>
            <asp:CheckBox id="CheckBoxA" runat="server" EnableViewState="False" Text="A"></asp:CheckBox>
            <asp:CheckBox id="CheckBoxB" runat="server" EnableViewState="False" Text="B"></asp:CheckBox>
            <asp:CheckBox id="CheckBoxC" runat="server" EnableViewState="False" Text="C"></asp:CheckBox>
        </p>
        <p>
            <asp:Button id="btnEnvoyer" onclick="btnEnvoyer_Click" runat="server" Text="Envoyer"></asp:Button>
            <asp:Button id="btnTree" onclick="btnTree_Click" runat="server" Text="Contrôles"></asp:Button>
        </p>
        <p>
            <asp:ListBox id="lstInfos" runat="server" EnableViewState="False" Rows="6" Height="131px"></asp:ListBox>
        </p>
    </form>
</body>
</html>

Bu düğmedeki [Click] olayını işlemek için [btnEnvoyer_Click] prosedürünü yazmamız gerekiyor. Bir radyo düğmesinin veya onay kutusunun durumu, [Checked] özniteliği ile belirlenir; bu öznitelik, kutu işaretliyse "true", aksi takdirde "false" değerini alır. Bu nedenle, [lstInfos] listesine altı radyo düğmesi ve onay kutusunun [Checked] özniteliğinin değerini yazmamız yeterlidir. Bunda özel bir zorluk olmadığı için, biraz yenilik yapalım:

<script runat="server">

    Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
      ' listbox'a bilgiler ekleniyor
      for each c as control in FindControl("frmControls").controls
          ' kontrol, CheckBox'ten türetilmiş mi?
          if TypeOf(c) is CheckBox then
              lstInfos.Items.Add(c.ID + " : " + Ctype(c,CheckBox).Checked.ToString)
          end if
      next
    End Sub

</script>

Sayfa, denetimlerden oluşan bir ağaç yapısı olarak görülebilir. Örneğimizde sayfamız metinler ve sunucu denetimleri içermektedir. Metinler, [LiteralControl] adlı özel bir denetim olarak görülür. En küçük metin bile, hatta iki denetim arasındaki boşluk dizisi bile bu denetimi oluşturur. Her kontrolün kendisini tanımlayan bir ID özniteliği vardır. Etiketlerde görünen öznitelik ID’tir:

            <asp:CheckBox id="CheckBoxA" runat="server" ></asp:CheckBox>

[LiteralControl] denetimlerini göz ardı edersek, incelenen sayfada şu denetimler bulunur:

  • [HtmlForm], [ID=frmControls] formudur. Bu form da bir denetim konteyneridir. Aşağıdaki denetimleri içerir:

-- [ID=RadioButton1], türü [RadioButton]

-- [ID=RadioButton2], türü [RadioButton]

-- [ID=RadioButton3], türü [RadioButton]

-- [ID=CheckBoxA], türü [CheckBox]

-- [ID=CheckBoxA], türü [CheckBox]

-- [ID= CheckBoxA] türü [CheckBox]

-- [ID=btnEnvoyer] türü [Button]

Bir denetim aşağıdaki özelliklere sahiptir:

[Control].Controls
varsa, [Control]’nin alt denetimlerini toplar
[Control].FindControl(ID)
[Control]'in alt denetim ağacının kökünde bulunan ve ID ile tanımlanan denetimi döndürür. Yukarıdaki örnekte: Page.FindControl("frmControls"), [HtmlForm] konteynerini belirtir. [RadioButton1] radyo düğmesine ulaşmak için şunu yazmanız gerekir
Page.FindControl("frmControls").FindControl("RadioButton1")
[Control].ID
[Control] kimliği

[btnEnvoyer_Click] prosedürünün koduna geri dönelim:

    Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
      ' bilgiler list kutusuna ekleniyor
      for each c as control in FindControl("frmControls").controls
          ' kontrol, CheckBox'ten türetilmiş mi?
          if TypeOf(c) is CheckBox then
              lstInfos.Items.Add(c.ID + " : " + Ctype(c,CheckBox).Checked.ToString)
          end if
      next
    End Sub

Formda bulunan radyo düğmelerinin ve onay kutularının durumunu görüntülemek istiyoruz. Formdaki tüm denetimleri tek tek inceliyoruz. Eğer mevcut denetim [CheckBox] sınıfından türetilmiş bir türdeyse, o denetimin [Checked] özelliğini görüntülüyoruz. [RadioButton] sınıfı, [CheckBox] sınıfından türetildiğinden, bu test her iki kontrol türü için de geçerlidir. Yukarıda gösterilen ekran görüntüsü, bir yürütme örneğini göstermektedir.

7.10. CheckBoxList ve RadioButtonList bileşenleri

Bazen, sayfayı tasarlarken henüz bilinmeyen değerler arasından kullanıcının seçim yapmasını sağlamak istenir. Bu seçenekler bir yapılandırma dosyasından, bir veritabanından vb. gelir ve yalnızca yürütme anında bilinir. Bu soruna yönelik çözümler mevcuttur ve biz de bunlarla karşılaştık. Kullanıcı yalnızca bir seçim yapabiliyorsa tek seçimli liste, birden fazla seçim yapabiliyorsa çoklu seçimli liste uygun olur. Estetik açıdan bakıldığında ve seçenek sayısı fazla değilse, tekli seçim listesi yerine radyo düğmeleri veya çoklu seçim listesi yerine onay kutuları kullanmak isteyebilirsiniz. Bu, [CheckBoxList] ve [RadioButtonList] bileşenleriyle mümkündür.

[CheckBoxList] ve [RadioButtonList] sınıfları, daha önce incelediğimiz [DropDownList] ve [ListBox] sınıflarıyla aynı [ListControl] sınıfından türetilmiştir. Bu nedenle, bu sınıflarda daha önce incelenen ve aslında [ListControl] sınıfına ait olan bazı özellik ve yöntemleri burada da göreceğiz.

Items
açılır menü öğelerinin [ListItemCollection] türündeki koleksiyonu. Bu koleksiyonun elemanları [ListItem] türündedir.
Items.Count
[Items] koleksiyonundaki öğe sayısı
Items(i)
listenin i numaralı öğesi - türü [ListItem]
Items.Add
koleksyona yeni bir öğe eklemek için [ListItem] [Items]
Items.Clear
[Items] koleksiyonundaki tüm öğeleri silmek için
Items.RemoveAt(i)
[Items] koleksiyonundan i numaralı öğeyi silmek için
SelectedItem
[Items] koleksiyonundaki, [ListItem] numaralı ilk öğe, [Selected] özelliğinin değeri "true" olan öğe
SelectedIndex
[Items] koleksiyonundaki önceki öğenin numarası

Bazı özellikler [CheckBoxList] ve [RadioButtonList] sınıflarına özgüdür:

RepeatDirection
Yatay veya dikey listeler için [horizontal] veya [vertical].

[Items] koleksiyonundaki öğeler, [ListItem] türündedir. Her bir [ListItem] öğesi, söz konusu nesnenin [CheckBoxList] mı yoksa [RadioButtonList] mi olduğuna bağlı olarak farklı bir etiket oluşturacaktır:

<input type="checkbox" [selected="selected"] value="V">Texte

Veya

<input type="radio" [selected="selected"] value="V">Texte

[ListItem] sınıfının bazı özelliklerini ve yöntemlerini aşağıda açıklıyoruz:

ListItem(String texte, String value)
yapıcı - text ve value özelliklerine sahip bir [ListItem] öğesi oluşturur. Bir ListItem(T,V) öğesi, duruma göre <input type="checkbox" value="V">T veya <input type="radio" value="V">T HTML etiketini oluşturur.
Selected
boole. Değer true ise, HTML listesindeki ilgili seçenek, [selected="selected"] özniteliğine sahip olacaktır. Bu öznitelik, tarayıcıya ilgili öğenin HTML listesinde seçili olarak görünmesi gerektiğini bildirir.
Text
HTML seçeneğindeki T metni <input type=".." value="V" [selected="selected"]>T
Value
HTML seçeneğinin Value özniteliğinin değeri <input type=".." value="V" [selected="selected"]>T

Aşağıdaki [form8b.aspx] sayfasını oluşturmayı planlıyoruz:

Image

no
ad
tür
özellikler
rol
1
RadioButtonList1
RadioButtonList
EnableViewState=true
Tekrar Yönü=yatay
radyo düğmeleri listesi
2
CheckBoxList1
CheckBoxList
EnableViewState=true
RepeatDirection=horizontal
onay kutuları listesi
3
btnEnvoyer
Düğme
 
[submit] düğmesi, [4]'te her iki listeden seçilen öğelerin listesini görüntüler
4
lstInfos
ListBox
EnableViewState=false
değer listesi

Sayfanın sunum kodu şöyledir:

<%@ Page Language="VB" autoeventwireup="false" %>
<script runat="server">
...
</script>
<html>
<head>
</head>
<body>
    <form id="frmControls" runat="server">
        <h3>Listes de cases à cocher
        </h3>
        <p>
            <asp:RadioButtonList id="RadioButtonList1" runat="server" RepeatDirection="Horizontal"></asp:RadioButtonList>
        </p>
        <p>
            <asp:CheckBoxList id="CheckBoxList1" runat="server" RepeatDirection="Horizontal"></asp:CheckBoxList>
        </p>
        <p>
            <asp:Button id="btnEnvoyer" onclick="btnEnvoyer_Click" runat="server" Text="Envoyer"></asp:Button>
        </p>
        <p>
            <asp:ListBox id="lstInfos" runat="server" EnableViewState="False" Rows="6"></asp:ListBox>
        </p>
    </form>
</body>
</html>

Doğrulama kodu şöyledir:

<script runat="server">

    Sub Page_Load(sender As Object, e As EventArgs) handles MyBase.Load
        ' kontrol ilk kez çağrılıyorsa listeler doldurulur
        if not IsPostBack then
            ' RadioButton listesi için metinler
          dim textesRadio() as String = {"1","2","3","4"}
          ' RadioButton listesi için metinler
          dim textesCheckBox() as  String = {"un","deux","trois","quatre"}
                 ' radyo listesinin doldurulması
            dim i as integer
            for i=0 to textesRadio.length-1
                RadioButtonList1.Items.Add(new ListItem(textesRadio(i)))
            next
             ' 1 numaralı öğenin seçilmesi
            RadioButtonList1.SelectedIndex=1
            ' onay kutusu listesini doldurma
            for i=0 to textesCheckBox.length-1
                CheckBoxList1.Items.Add(new ListItem(textesCheckBox(i)))
            next
        end if
    end sub


    Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
      ' lstinfos liste kutusuna bilgiler ekleniyor
      affiche(RadioButtonList1)
      affiche(CheckBoxList1)
    End Sub

    sub affiche(l1 as ListControl)
      ' l1'den seçilen öğelerin değerlerini görüntüler
       ' Yapılması gereken bir şey var ?
      if l1.selectedindex=-1 then return
      dim i as integer
      ' sonundan başlıyoruz
      for i= 0 to l1.items.count-1
        ' seçildi mi?
        if l1.items(i).selected then
          lstInfos.Items.Add("["+TypeName(l1)+"] ["+l1.items(i).text+"] sélectionné")
        end if
      next
    end sub

</script>

Sayfa her çalıştırıldığında yürütülen [Page_Load] prosedüründe, iki liste de başlatılır. Bunların her seferinde başlatılmasını önlemek için, [IsPostBack] özelliği kullanılarak bu işlem sadece ilk seferde yapılır. Sonraki seferlerde listeler, [VIEWSTATE] mekanizması tarafından otomatik olarak yeniden oluşturulur. Sayfa görüntülendikten sonra kullanıcı belirli kutuları işaretler ve [Envoyer] düğmesini kullanır. Ardından form değerleri, formun kendisine gönderilir. [Page_Load] yürütüldükten sonra, [btnEnvoyer_Click] prosedürü yürütülür. Bu prosedür, [lstInfos] listesini doldurmak için [affiche] prosedürünü çağırır. Bu prosedür, parametre olarak [ListControl] türünde bir nesne alır; bu sayede, [ListControl] sınıfından türetilen [RadioButtonList] veya [CheckBoxList] nesneleri ayırt edilmeden gönderilebilir. [lstInfos] listesinin [EnableViewState] özniteliği, [false] olarak ayarlanabilir; çünkü bu listenin durumu, farklı istekler arasında korunması gerekmez.

7.11. Panel bileşenleri, LinkButton

<asp:panel> etiketi, bir sayfaya denetimler içeren bir kapsayıcı eklemeye olanak tanır. Bu kapsayıcının avantajı, bazı özelliklerinin içerdiği tüm denetimlere uygulanmasıdır. [Visible] özelliği de buna bir örnektir. Bu özellik, tüm sunucu denetimleri için geçerlidir. Bir kapsayıcının [Visible=false] özelliği varsa, içindeki her bir denetim kendi [Visible] özelliği tarafından kontrol edilir. [Visible=false] özelliğine sahipse, konteyner ve içindeki her şey görüntülenmez. Bu, konteynerdeki her bir denetimin [Visible] özelliğini yönetmekten daha basit olabilir.

<asp:LinkButton> etiketi, bir sayfanın sunum koduna bir bağlantı eklemeye olanak tanır. Bu etiket, [Button] düğmesiyle benzer bir işleve sahiptir. Aslında, kendisine atanan bir JavaScript işlevi sayesinde istemci tarafında bir POST işlemi tetikler. Aşağıdaki görünümü elde etmek için bir [form9.aspx] sayfası oluşturuyoruz:

Image

no
ad
tür
özellikler
rol
1
Panel1
Panel
EnableViewState=true
denetimler için konteyner
2
ListBox1
ListBox
EnableViewState=true
üç değerden oluşan bir liste
3
lnkCacher
LinkButton
EnableViewState=false
konteyneri gizlemek için bağlantı

Kapsayıcı gizlendiğinde yeni bir bağlantı görünür:

Image

no
ad
tür
özellikler
rol
4
lnkVoir
LinkButton
EnableViewState=false
konteyneri görüntülemek için bağlantı

Sayfanın sunum kodu şöyledir:

<html>
<head>
</head>
<body>
    <form runat="server">
        <p>
            <asp:Panel id="Panel1" runat="server" BorderStyle="Ridge" BorderWidth="1px">
                <p>
                    Conteneur 
                </p>
                <p>
                    <asp:ListBox id="ListBox1" runat="server">
                        <asp:ListItem Value="1">un</asp:ListItem>
                        <asp:ListItem Value="2">deux</asp:ListItem>
                        <asp:ListItem Value="3" Selected="True">trois</asp:ListItem>
                    </asp:ListBox>
                </p>
            </asp:Panel>
        </p>
        <p>
            <asp:LinkButton id="lnkVoir" onclick="lnkVoir_Click" runat="server">Voir le conteneur</asp:LinkButton>
        </p>
        <p>
            <asp:LinkButton id="lnkCacher" onclick="lnkCacher_Click" runat="server">Cacher le conteneur</asp:LinkButton>
        </p>
    </form>
</body>
</html>

Bu kodun [ListBox1] listesini üç değerle başlattığına dikkat edelim. Her iki bağlantıdaki [Clic] olay işleyicileri şunlardır:

<%@ Page Language="VB" %>
<script runat="server">

    Sub Page_Load(sender As Object, e As EventArgs)
...
    end sub

    Sub lnkVoir_Click(sender As Object, e As EventArgs)
        ' 1 numaralı konteyneri görüntüler
        panel1.Visible=true
         ' bağlantıları değiştir
        lnkVoir.visible=false
        lnkCacher.visible=true
    End Sub

    Sub lnkCacher_Click(sender As Object, e As EventArgs)
        ' 1 numaralı konteyneri gizle
        panel1.Visible=false
         ' bağlantıları değiştir
        lnkVoir.visible=true
        lnkCacher.visible=false
    End Sub
</script>

Formu başlatmak için [Page_Load] prosedürünü kullanacağız. Bunu ilk istekte yapacağız (IsPostBack=false):

<%@ Page Language="VB" %>
<script runat="server">

    Sub Page_Load(sender As Object, e As EventArgs)
        ' ilk kez
        if not IsPostBack then
            ' konteyneri gösterir
            lnkVoir_Click(nothing,nothing)
        end if
    end sub
.....
</script>

7.12. Devam etmek gerekirse...

Önceki paragraflarda bir dizi sunucu bileşeni tanıtılmıştır. Her seferinde bu bileşenlerin yalnızca bazı özellikleri ele alınmıştır. Bu bileşenleri daha ayrıntılı olarak incelemek isteyen okuyucu, çeşitli yollara başvurabilir:

  • WebMatrix gibi bir IDE dosyası kullanarak bir bileşenin özelliklerini keşfedebilir. Bu dosya, bir formda kullanılan bileşenlerin temel özelliklerini ortaya koymaktadır
  • .NET belgelerine göz atarak her bir sunucu bileşenine karşılık gelen sınıfların tamamını keşfedebilir. Bileşeni tam olarak kavramak için tercih edilmesi gereken yöntem budur. Burada, bileşenlere giden sınıf ağacını, her birinin özelliklerini, yöntemlerini, oluşturucularını ve olaylarını bulabilirsiniz. Ayrıca belgelerde bazen örnekler de sunulmaktadır.

Bu bölümde, [WebMatrix] "hepsi bir arada" tekniğini kullandık; bu teknikte, bir sayfanın sunum kodu ile kontrol kodu aynı dosyaya yerleştirilir. Genel olarak, bu yöntemi önermiyoruz; bunun yerine, daha önce kullandığımız ve bu iki kodu ayrı iki dosyaya yerleştiren [codebehind] yöntemini tavsiye ediyoruz. Bu ayrımın avantajının, web uygulamasını çalıştırmaya gerek kalmadan kontrol kodunun derlenebilmesi olduğunu hatırlatmak isteriz. Ayrıca, örneklerimiz – ki bunu bölümün başından itibaren açıklamıştık – oldukça özel bir profile sahipti: bunlar, istemci ile sunucu arasında art arda gelen istek-yanıt döngülerinde karşılıklı olarak gönderilen tek bir formdan oluşuyordu; ilk istemci isteği bir GET, sonraki istekler ise POST idi.

7.13. Sunucu Bileşenleri ve Uygulama Denetleyicisi

Önceki bölümlerde birkaç web uygulaması geliştirdik. Bunların tümü, uygulamayı birbirinden net bir şekilde ayrılmış bloklara bölen ve bakımını kolaylaştıran MVC (Model-Görünüm-Denetleyici) mimarisine göre oluşturulmuştu. O zamanlar kullanıcı arayüzlerimizi standart HTML etiketleriyle oluşturuyorduk. Az önce gördüklerimizden yola çıkarak, artık sunucu bileşenlerini kullanmak istememiz doğaldır. Daha önce uzun uzadıya incelediğimiz bir sorunu, yani vergi hesaplamasını tekrar ele alalım. Bu sorunun MVC mimarisi şöyleydi:

Image

Uygulamanın iki görünümü vardır: [formulaire.aspx] ve [erreurs.aspx]. [formulaire.aspx] görünümü, [main.aspx] URL'si ilk kez istendiğinde görüntülenir:

Image

Kullanıcı formu doldurur:

Image

ve [Calculer] düğmesini kullanarak aşağıdaki yanıtı alır:

Image

MVC uygulamasında, tüm istekler denetleyiciden geçmelidir; bu örnekte [main.aspx]. Bu, [formulaire.aspx] formunun kullanıcı tarafından doldurulmasının ardından, [formulaire.aspx]'e değil, [main.aspx]'e gönderilmesi gerektiği anlamına gelir. [formulaire.aspx] kullanıcı arayüzünü ASP sunucu bileşenleriyle oluşturursak, bu kesinlikle mümkün olmaz. Bunu anlamak için, bir <asp:button> bileşeni içeren bir [formtest.aspx] formu oluşturalım:

<%@ Page Language="VB" EnableViewState="false"%>
<html>
<head>
    <title>test</title>
</head>
<body>
    <form action="main.aspx" runat="server">
        <p>
            <asp:Button id="btnTest" runat="server" EnableViewState="false" Text="Test"></asp:Button>
        </p>
    </form>
</body>
</html>

<form..> etiketindeki [action="main.aspx"] özniteliğine dikkat edin. Bu uygulamayı çalıştıralım. Giriş sayfasında sadece bir düğme bulunmaktadır:

Image

Sunucu tarafından gönderilen HTML koduna bir göz atalım:

<html>
<head>
    <title>test</title>
</head>
<body>
    <form name="_ctl0" method="post" action="formtest.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwtNTMwNzcxMzI0Ozs+" />

        <p>
            <input type="submit" name="btnTest" value="Test" id="btnTest" />
        </p>

    </form>
</body>
</html>

Görüldüğü üzere, formdaki POST etiketinin hedefi, formun kendisi olan [action="formtest.aspx"]'tir; oysa biz [formtest.aspx]'te HTML etiketini yazmıştık. Sunucu:

    <form action="main.aspx" runat="server">

<form> etiketinin [runat="server"] özniteliği, sunucu bileşenlerinin kullanımı nedeniyle zorunludur. Bu özniteliği eklemezsek derleme hatası oluşur. Bu özniteliği eklediğimizde ise <form> etiketinin [action] özniteliği yok sayılır. Sunucu her zaman formun kendisine işaret eden bir [action] özniteliği oluşturur. Buradan, bir MVC uygulamasında <form ... runat="server"> etiketiyle oluşturulmuş formların kullanılamayacağı sonucu çıkar. Oysa bu etiket, kullanıcı girdilerini alan tüm ASP sunucu bileşenleri için vazgeçilmezdir. Diğer bir deyişle, bir MVC uygulamasında ASP sunucu formları kullanılamaz. Bu büyük bir keşif. Nitekim ASP.NET'in pazarlama açısından en güçlü yanlarından biri, bir web uygulamasını Windows uygulaması gibi oluşturabilmektir. Uygulamamız MVC mimarisine uymuyorsa bu doğrudur, ancak uymuyorsa daha da doğrudur. Oysa MVC mimarisi, günümüz web geliştirme dünyasında göz ardı edilmesi zor olan temel bir kavram gibi görünüyor.

Farklı görünüm sayısı az olan uygulamalar için, aşağıdaki yöntem sayesinde MVC mimarisini ASP bileşenli formlarla birlikte kullanmak mümkündür:

  • uygulama, denetleyici görevi gören tek bir sayfadan oluşur
  • görünümler, bu sayfada her bir görünüm için ayrı bir kapsayıcı olacak şekilde farklı kapsayıcılara dönüştürülür. Bir görünümü görüntülemek için, o görünümü içeren kapsayıcıyı görünür hale getirip diğerlerini gizleriz

Bu, şimdi birkaç örnekte uygulayacağımız zarif bir çözümdür

7.14. MVC uygulamaları örnekleri (ASP sunucu bileşenleri ile)

7.14.1. Örnek 1

Bu ilk örnekte, daha önce tanıttığımız sunucu bileşenlerini kullanıyoruz. [form10.aspx] sayfası şu şekilde olacaktır:

Yukarıdaki sol ekran görüntüsü, müşteriye sunulan formdur. Müşteri bu formu doldurur ve [Envoyer] ile onaylar. Sunucu, kullanıcıya girilen değerlerin listesini gösteren bir sayfa gönderir (sağdaki ekran görüntüsü). Bir bağlantı sayesinde kullanıcı forma geri dönebilir. Formu, onayladığı haliyle bulur. [form10.aspx]'in sunum kodu şöyledir:

<html>
<head>
    <title>Exemple</title> <script language="javascript">
        function effacer(){
            alert("Vous avez cliqué sur [Effacer]")
        }
    </script>
</head>
<body>
    <p>
        Gestion d'un formulaire
    </p>
    <p>
        <hr />
    </p>
    <form runat="server">
        <p>
            <asp:Panel id="panelinfo" runat="server" EnableViewState="False">
                <p>
                    Liste des valeurs obtenues
                </p>
                <p>
                    <asp:ListBox id="lstInfos" runat="server" EnableViewState="False"></asp:ListBox>
                </p>
                <p>
                    <asp:LinkButton id="LinkButton1" onclick="LinkButton1_Click" runat="server">Retour au formulaire</asp:LinkButton>
                </p>
                <p>
                    <hr />
                </p>
            </asp:Panel>
        </p>
        <p>
            <asp:Panel id="panelform" runat="server" >
                <table>
                    <tbody>
                        <tr>
                            <td>
                                Etes-vous marié(e)</td>
                            <td>
                                <asp:RadioButton id="rdOui" runat="server"  GroupName="rdmarie"></asp:RadioButton>
                                Oui<asp:RadioButton id="rdNon" runat="server"  GroupName="rdmarie" Checked="True"></asp:RadioButton>
                                Non</td>
                        </tr>
                        <tr>
                            <td>
                                Cases à cocher</td>
                            <td>
                                <asp:CheckBox id="chk1" runat="server"></asp:CheckBox>
                                1<asp:CheckBox id="chk2" runat="server"></asp:CheckBox>
                                2<asp:CheckBox id="chk3" runat="server"></asp:CheckBox>
                                3</td>
                        </tr>
                        <tr>
                            <td>
                                Champ de saisie</td>
                            <td>
                                <asp:TextBox id="txtSaisie" runat="server"  MaxLength="20" Columns="20"></asp:TextBox>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                Mot de passe</td>
                            <td>
                                <asp:TextBox id="txtmdp" runat="server"  MaxLength="10" Columns="10" TextMode="Password"></asp:TextBox>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                Boîte de saisie</td>
                            <td>
                                <asp:TextBox id="txtArea" runat="server"  Columns="20" TextMode="MultiLine" Rows="3"></asp:TextBox>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                Liste déroulante</td>
                            <td>
                                <asp:DropDownList id="cmbValeurs" runat="server"></asp:DropDownList>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                Liste à choix unique</td>
                            <td>
                                <asp:ListBox id="lstSimple" runat="server"></asp:ListBox>
                                <asp:Button id="btnRazSimple" onclick="btnRazSimple_Click" runat="server" EnableViewState="False" Text="Raz"></asp:Button>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                Liste à choix multiple</td>
                            <td>
                                <asp:ListBox id="lstMultiple" runat="server" SelectionMode="Multiple"></asp:ListBox>
                                <asp:Button id="razMultiple" onclick="razMultiple_Click" runat="server" EnableViewState="False" Text="Raz"></asp:Button>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                Champ caché</td>
                            <td>
                                <asp:Label id="lblSecret" runat="server" visible="False"></asp:Label></td>
                        </tr>
                        <tr>
                            <td>
                                Bouton simple</td>
                            <td>
                                <input id="btnEffacer" onclick="effacer()" type="button" value="Effacer" /></td>
                        </tr>
                        <tr>
                            <td>
                                Bouton [reset]</td>
                            <td>
                                <input id="btnReset" type="reset" value="Rétablir" /></td>
                        </tr>
                        <tr>
                            <td>
                                Bouton [submit]</td>
                            <td>
                                <asp:Button id="btnEnvoyer" onclick="btnEnvoyer_Click" runat="server" EnableViewState="False" Text="Envoyer"></asp:Button>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </asp:Panel>
        </p>
    </form>
</body>
</html>

Sayfada her bir görünüm için birer tane olmak üzere iki konteyner bulunmaktadır: form görünümü için [panelform], bilgi görünümü için [panelinfo]. [panelForm] konteynerindeki bileşenlerin listesi şöyledir:

ad
tür
özellikler
rol
panelform
Panel
EnableViewState=true
form görünümü
rdOui
rdNon
RadioButton
EnableViewState=true
GroupName=rdmarie
radyo düğmeleri
chk1
chk2
chk3
CheckBox
EnableViewState=true
onay kutuları
txtSaisie
TextBox
EnableViewState=true
giriş alanı
txtMdp
TextBox
EnableViewState=true
korumalı giriş alanı
txtArea
TextBox
EnableViewState=true
çok satırlı giriş kutusu
cmbValeurs
DropDownList
EnableViewState=true
açılır liste
lstSimple
ListBox
EnableViewState=true
Seçim Modu=Tek
tek seçim listesi
btnRazSimple
Düğme
EnableViewState=false
lstSimple'teki tüm öğelerin seçimini kaldır
lstMultiple
ListBox
EnableViewState=true
SelectionMode=Multiple
çoklu seçim listesi
btnRazMultiple
Düğme
EnableViewState=false
lstMultiple'teki tüm öğelerin seçimini kaldır
lblSecret
Etiket
EnableViewState=true
Visible=false
gizli alan
btnEffacer
HTML standart
 
bir uyarı gösterir
btnEnvoyer
Düğme
EnableViewState=false
formdaki [submit] düğmesi
btnReset
HTML standart
 
formdaki [reset] düğmesi

[VIEWSTATE]'in bileşenler üzerindeki rolü burada önemlidir. Düğmeler hariç tüm bileşenler [EnableViewState=true] özelliğine sahip olmalıdır. Bunun nedenini anlamak için uygulamanın işleyişini hatırlamak gerekir. [txtSaisie] alanının [EnableViewState=false] özelliğine sahip olduğunu varsayalım:

  1. müşteri ilk olarak [form10.aspx] sayfasını ister. Form görünümünü alır
  2. formu doldurur ve [Envoyer] düğmesiyle gönderir. Giriş alanları bu şekilde gönderilir ve sunucu, sunucu bileşenlerine gönderilen değeri veya varsa [VIEWSTATE] durumlarını atar. Böylece [txtSaisie] alanına kullanıcı tarafından girilen değer atanır. Ayrıca bu adımda, [VIEWSTATE] durumu hiçbir işe yaramaz. İşlemin sonucu olarak, [informations] görünümü gönderilir; aslında bu, her zaman [form10.aspx] sayfasıdır, ancak farklı bir konteyner görüntülenir.
  3. Kullanıcı bu yeni görünümü inceler ve [Retour au formulaire] bağlantısını kullanarak önceki sayfaya geri döner. Ardından POST aracılığıyla [form10.aspx]'e bir istek gönderilir. Bu durumda gönderilen en fazla bir değer vardır: kullanıcı tarafından bilgi listesinden seçilen değer; bu bilgi daha sonra kullanılmamaktadır. Her halükarda, [txtSaisie] alanı gönderilmemiştir.
  4. Sunucu, POST'i alır ve sunucu bileşenlerine gönderilen değeri atar; eğer bir durumları varsa, [VIEWSTATE] durumunu atar. Burada, [txtNom]'e gönderilen bir değer yoktur. [EnableViewState] özniteliği [false] ise, ona boş dize atanacaktır. Kullanıcı tarafından girilen değeri almasını istediğimiz için, [EnableViewState=true] özelliğine sahip olması gerekir.

[panelinfo] konteyneri aşağıdaki denetimlere sahiptir:

ad
tür
özellikler
rol
panelinfo
Panel
EnableViewState=false
bilgi görünümü
lstInfos
ListBox
EnableViewState=false
kullanıcı tarafından girilen değerleri özetleyen bilgi listesi
LinkButton1
LinkButton
EnableViewState=false
form sayfasına geri dönme bağlantısı

Testler sırasında, yukarıdaki sunum kodunun oluşturduğu HTML koduna bakıldığında, gizli alan [lblSecret] için oluşturulan kod şaşırtıcı gelebilir:

                    <tr>
                        <td>
                            Champ caché</td>
                        <td></td>
                    </tr>

[lblSecret] bileşeni, [Visible=false] özelliğine sahip olduğu için HTML koduna çevrilmez. Ancak [EnableViewState=true] özelliğine sahip olduğu için, değeri yine de [__VIEWSATE] gizli alanında korunacaktır. Dolayısıyla, testlerin de göstereceği gibi bu değeri geri alabileceğiz.

Geriye olay işleyicilerini yazmak kalıyor. [Page_Load]'te formu başlatacağız:

Sub page_Load(sender As Object, e As EventArgs)
         ' ilk seferde, öğeler başlatılır
          ' sonraki seferlerde, bu öğeler VIEWSTATE aracılığıyla değerlerini geri alır
         if IsPostBack then return
         ' formu başlat
          ' panelinfo görüntülenmiyor
         panelinfo.visible=false
         ' form paneli görüntüleniyor
         panelform.visible=true
         ' radyo düğmeleri
         rdNon.Checked=true
         ' onay kutuları
         chk2.Checked=true
          ' giriş alanı
         txtSaisie.Text="qqs mots"
          ' şifre alanı
         txtMdp.Text="ceciestsecret"
         ' giriş kutusu
         txtArea.Text="ligne"+ControlChars.CrLf+"ligne2"+ControlChars.CrLf
         ' açılır menü
         dim i as integer
         for i=1 to 4
             cmbValeurs.Items.Add(new ListItem("choix"+i.ToString,i.ToString))
         next
         cmbValeurs.SelectedIndex=1
         ' tek seçimli liste
         for i=1 to 7
             lstSimple.Items.Add(new ListItem("simple"+i.ToString,i.ToString))
         next
         lstSimple.SelectedIndex=0
         ' çoklu seçim listesi
         for i=1 to 10
             lstMultiple.Items.Add(new ListItem("multiple"+i.ToString,i.ToString))
         next
         lstMultiple.Items(0).Selected=true
         lstMultiple.Items(2).Selected=true
         ' gizli alan
         lblSecret.Text="secret"
End Sub

[lstRazSimple] ve [lstMultiple] düğmelerine tıklayın:

Sub btnRazSimple_Click(sender As Object, e As EventArgs)
    ' tekli liste sıfırlama
    lstSimple.SelectedIndex=-1
End Sub

Sub razMultiple_Click(sender As Object, e As EventArgs)
    ' çoklu listeyi sıfırla
    lstMultiple.SelectedIndex=-1
End Sub

[Envoyer] düğmesine tıklandığında:

Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
    ' bilgi paneli görünür hale getirilir ve form paneli gizlenir
  panelinfo.Visible=true
  panelform.visible=false
  ' gönderilen değerler alınır ve lstInfos'e aktarılır
   ' radyo düğmeleri
  dim info as string="état marital : "+iif(rdoui.checked,"marié"," non marié")
  affiche(info)
   ' onay kutuları
  info=" cases cochées : "+iif(chk1.checked,"1 oui","1 non")+","+ _
      iif(chk2.checked,"2 oui","2 non")+","+iif(chk3.checked,"3 oui","3 non")
  affiche(info)
   ' giriş alanı
  affiche("champ de saisie : " + txtSaisie.Text.Trim)
   ' şifre
  affiche("mot de passe : " + txtMdp.Text.Trim)
   ' giriş kutusu
  dim lignes() as String
  lignes=new Regex("\r\n").Split(txtArea.Text.Trim)
  dim i as integer
  for i=0 to lignes.length-1
      lignes(i)="["+lignes(i).Trim+"]"
  next
  affiche("Boîte de saisie : " + String.Join(",",lignes))
   ' açılır menü
  affiche("éléments sélectionnés dans combo : "+selection(cmbValeurs))
   ' basit liste
  affiche("éléments sélectionnés dans liste simple : "+selection(lstSimple))
   ' çoklu liste
  affiche("éléments sélectionnés dans liste multiple : "+selection(lstMultiple))
   ' gizli alan
  affiche ("Champ caché : " + lblSecret.Text)
End Sub

sub affiche(msg as String)
    ' lstInfos'te mesaj görüntüler
    lstInfos.Items.Add(msg)
end sub

       function selection(liste as ListControl) as string
           ' liste öğelerini tarar
            ' seçili olanları bulmak için
           dim i as integer
           dim info as string=""
           for i=0 to liste.Items.Count-1
               if liste.Items(i).Selected then info+="[" + liste.Items(i).Text + "]"
           next
           return info
       end function

Son olarak [Retour vers le formulaire ] bağlantısına tıklayın:

Sub LinkButton1_Click(sender As Object, e As EventArgs)
    ' form görüntülenir ve bilgi paneli gizlenir
    panelform.visible=true
    panelinfo.visible=false
End Sub

7.14.2. Örnek 2

Burada, daha önce ele alınmış olan ve standart HTML formlarını içeren bir uygulamayı ele alıyoruz. Bu uygulama, vergi hesaplamaları için simülasyonlar yapmaya olanak tanır. Uygulama, burada tekrar üzerinde durmayacağımız [impot] sınıfına dayanmaktadır. Bu sınıf, OLEDB veri kaynağında bulunan verilere ihtiyaç duyar. Örnek olarak, ACCESS veri kaynağı kullanılacaktır.

7.14.2.1. Uygulamanın MVC yapısı

Uygulamanın MVC yapısı şu şekildedir:

Image

Bu üç görünüm, [main.aspx] denetleyicisinin sunum koduna konteynerler şeklinde eklenecektir. Dolayısıyla bu uygulamanın tek bir sayfası vardır: [main.aspx].

7.14.2.2. Web uygulamasının görünümleri

[formulaire] görünümü, bir kullanıcının vergisinin hesaplanmasına olanak tanıyan bilgi giriş formudur:

Image

Kullanıcı formu doldurur:

Image

[Envoyer] düğmesini kullanarak vergisinin hesaplanmasını talep eder. Aşağıdaki [simulations] görünümünü alır:

Image

Yukarıdaki bağlantı aracılığıyla forma geri döner. Formu, girdiğindeki haliyle bulur. Giriş yaparken hatalar yapabilir:

Image

Bu hatalar, [erreurs] ekranı aracılığıyla kendisine bildirilir:

Image

Yukarıdaki bağlantıdan forma geri döner. Formu, girdiğiniz haliyle bulur. Yeni simülasyonlar yapabilir:

Image

Böylece, bir simülasyon daha eklenmiş [simulations] görünümüne ulaşır:

Image

Son olarak, veri kaynağı mevcut değilse, bu durum [erreurs] görünümünde kullanıcıya bildirilir:

Image

7.14.2.3. Uygulamanın sunum kodu

[main.aspx] sayfasının tüm görünümleri bir araya getirdiğini hatırlayalım. Bu, üç kapsayıcı içeren tek bir formdur:

  • [panelform], [formulaire] görünümü için
  • [panelerreurs], [erreurs] görünümü için
  • [panelsimulations], [simulations] görünümü için

Görsel kod ile kontrol kodunu iki ayrı dosyada ayırmaya geri dönüyoruz. İlki [main.aspx] dosyasında, ikincisi ise [main.aspx.vb] dosyasında yer alacaktır. [main.aspx] dosyasındaki kod şu şekildedir:


<%@ page codebehind="main.aspx.vb" inherits="vs.main" AutoEventWireUp="false" %>
<HTML>
    <HEAD>
        <title>Calcul d'impôt </title>
    </HEAD>
    <body>
        <P>Calcul de votre impôt</P>
        <HR width="100%" SIZE="1">
        <FORM id="Form1" runat="server">
            <asp:panel id="panelform" Runat="server">
                <TABLE id="Table1" cellSpacing="1" cellPadding="1" border="0">
                    <TR>
                        <TD height="19">Etes-vous marié(e)</TD>
                        <TD height="19">
                            <asp:RadioButton id="rdOui" runat="server" GroupName="rdMarie"></asp:RadioButton>Oui
                            <asp:RadioButton id="rdNon" runat="server" GroupName="rdMarie" Checked="True"></asp:RadioButton>Non</TD>
                    </TR>
                    <TR>
                        <TD>Nombre d'enfants</TD>
                        <TD>
                            <asp:TextBox id="txtEnfants" runat="server" MaxLength="3" Columns="3"></asp:TextBox></TD>
                    </TR>
                    <TR>
                        <TD>Salaire annuel (euro)</TD>
                        <TD>
                            <asp:TextBox id="txtSalaire" runat="server" MaxLength="10" Columns="10"></asp:TextBox></TD>
                    </TR>
                </TABLE>
                <P>
                    <asp:Button id="btnCalculer" runat="server" Text="Calculer"></asp:Button>
                    <asp:Button id="btnEffacer" runat="server" Text="Effacer"></asp:Button></P>
            </asp:panel>
          <asp:panel id="panelerreurs" runat="server">
                <P>Les erreurs suivantes se sont produites :</P>
                <P>
                    <asp:Literal id="erreursHTML" runat="server"></asp:Literal></P>
                <P></P>
                <asp:LinkButton id="lnkForm1" runat="server">Retour au formulaire</asp:LinkButton>
            </asp:panel>
          <asp:panel id="panelsimulations" runat="server">
                <P>
                    <TABLE>
                        <TR>
                            <TH>
                                Marié</TH>
                            <TH>
                                Enfants</TH>
                            <TH>
                                Salaire annuel</TH>
                            <TH>
                                Impôt à payer (euro)</TH></TR>
                        <asp:Literal id="simulationsHTML" runat="server"></asp:Literal></TABLE>
                    <asp:LinkButton id="lnkForm2" runat="server">Retour au formulaire</asp:LinkButton></P>
            </asp:panel>
      </FORM>
    </body>
</HTML>

Üç konteyneri tanımladık. Bunların hepsinin <form runat="server"> etiketinin içinde yer aldığına dikkat edin. Bu zorunludur; çünkü sunucu bileşenlerinin avantajlarından yararlanmak istiyorsak, bunların bu tür bir etiket içine yerleştirilmesi gerekir. Burada dikkat edilmesi gereken önemli nokta, istemci ile web sunucusu arasında alışverişi yapılacak tek bir formun olmasıdır. Dolayısıyla, bu bölümün tamamında sunucu bileşenleri ile ilgili olarak kullanılan yapılandırmanın tam da içindeyiz. Her bir kapsayıcının bileşenlerini ayrıntılı olarak inceleyelim:

[panelform] konteyneri:

ad
tür
özellikler
rol
panelform
Panel
EnableViewState=true
form görünümü
rdOui
rdNon
RadioButton
EnableViewState=true
GroupName=rdmarie
radyo düğmeleri
txtEnfants
TextBox
EnableViewState=true
çocuk sayısı
txtSalaire
TextBox
EnableViewState=true
yıllık maaş
btnCalculer
Düğme
 
formdaki [submit] düğmesi - vergi hesaplamasını başlatır
btnEffacer
Düğme
 
Formdaki [submit] düğmesi - formu temizler

[panelerreurs] konteyneri:

ad
tür
özellikler
rol
panelerreurs
Panel
EnableViewState=true
hata görünümü
lnkForm1
LinkButton
EnableViewState=true
form bağlantısı
erreursHTML
Literal
 
hata listesindeki HTML kodu

[panelsimulations] konteyneri:

ad
tür
özellikler
rol
panelsimulations
Panel
EnableViewState=true
simülasyon görünümü
lnkForm2
LinkButton
EnableViewState=true
form bağlantısı
simulationsHTML
Literal
 
HTML kodlu simülasyon listesi bir tabloda HTML

7.14.2.4. Uygulamanın kontrol kodu

Uygulama kontrol kodu, [global.asax.vb] ve [main.aspx.vb] dosyalarında yer almaktadır. [global.asax] dosyası şu şekilde tanımlanmıştır:

<%@ Application src="Global.asax.vb" Inherits="Global" %>

[global.asax.vb] dosyası ise şöyledir:


Imports System
Imports System.Web
Imports System.Web.SessionState
Imports st.istia.univangers.fr
Imports System.Configuration
Imports System.Collections

Public Class Global
    Inherits System.Web.HttpApplication

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' bir import nesnesi oluşturulur
        Dim objImpot As impot
        Try
            objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
            ' nesneyi uygulamaya eklenir
            Application("objImpot") = objImpot
            ' hata yok
            Application("erreur") = False
        Catch ex As Exception
            'hata oluştu, uygulamaya kaydedilir
            Application("erreur") = True
            Application("message") = ex.Message
        End Try
    End Sub

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' oturumun başlangıcı - boş bir simülasyon listesi oluşturulur
        Session.Item("simulations") = New ArrayList
    End Sub
End Class

Uygulama başlatıldığında (uygulamaya yapılan ilk istek), [Application_Start] prosedürü yürütülür. Bu prosedür, verilerini OLEDB kaynağından alan [impot] türünde bir nesne oluşturmaya çalışır. Okuyucu, bu sınıfın tanımlandığı 5. bölümü, unutmuşsa, okumasını öneririz. Veri kaynağı mevcut değilse, [impot] nesnesinin oluşturulması başarısız olabilir. Bu durumda, hata uygulamada kaydedilir; böylece sonraki tüm sorgular, nesnenin düzgün bir şekilde başlatılamadığını bilir. Oluşturma işlemi başarılı olursa, oluşturulan [impot] nesnesi de uygulamada kaydedilir. Bu nesne, tüm vergi hesaplama sorguları tarafından kullanılacaktır. Bir müşteri ilk isteğini gönderdiğinde, [Application_Start] yordamı tarafından kendisi için bir oturum oluşturulur. Bu oturum, müşterinin gerçekleştireceği çeşitli vergi hesaplama simülasyonlarını kaydetmek amacıyla kullanılır. Bu simülasyonlar, "simulations" oturum anahtarıyla ilişkilendirilmiş bir [ArrayList] nesnesinde saklanır. Oturum başladığında, bu anahtar boş bir [ArrayList] nesnesine atanır. Uygulama için gerekli bilgiler, [wenConfig] yapılandırma dosyasına yerleştirilir:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key="chaineConnexion" value="Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=D:\data\serge\devel\aspnet\poly\webforms\vs\impots5\impots.mdb" />
    </appSettings>
</configuration>

[chaineConnexion] anahtarı, OLEDB kaynağına bağlantı dizesini belirtir. Kontrol kodunun diğer kısmı [main.aspx.vb]'te bulunur:


Imports System.Collections
Imports Microsoft.VisualBasic
Imports st.istia.univangers.fr
Imports System

Public Class main
    Inherits System.Web.UI.Page

    Protected WithEvents rdOui As System.Web.UI.WebControls.RadioButton
    Protected WithEvents rdNon As System.Web.UI.WebControls.RadioButton
    Protected WithEvents txtEnfants As System.Web.UI.WebControls.TextBox
    Protected WithEvents txtSalaire As System.Web.UI.WebControls.TextBox
    Protected WithEvents btnCalculer As System.Web.UI.WebControls.Button
    Protected WithEvents btnEffacer As System.Web.UI.WebControls.Button
    Protected WithEvents panelform As System.Web.UI.WebControls.Panel
    Protected WithEvents lnkForm1 As System.Web.UI.WebControls.LinkButton
    Protected WithEvents lnkForm2 As System.Web.UI.WebControls.LinkButton
    Protected WithEvents panelerreurs As System.Web.UI.WebControls.Panel
    Protected WithEvents panelsimulations As System.Web.UI.WebControls.Panel
    Protected WithEvents simulationsHTML As System.Web.UI.WebControls.Literal
    Protected WithEvents erreursHTML As System.Web.UI.WebControls.Literal

    ' yerel değişkenler

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...
    End Sub

    Private Sub afficheFormulaire()
...
    End Sub

    Private Sub afficheSimulations(ByRef simulations As ArrayList, ByRef lien As String)
...
    End Sub

    Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
...
    End Sub

    Private Function checkData() As ArrayList
...
    End Function

    Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
....
    End Sub

    Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
...
    End Sub

    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
...
    End Sub

    Private Sub razForm()
...
    End Sub
End Class

Le premier événement traité par le code est [Page_Load] :

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' öncelikle, uygulamanın durumuna bakılıyor
        If CType(Application("erreur"), Boolean) Then
            ' uygulama başlatılamadı
            ' hata görünümünü görüntülüyoruz
            Dim erreurs As New ArrayList
            erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
            afficheErreurs(erreurs, "")
            Exit Sub
        End If
        ' hata yok - ilk istekte form görüntülenir
        If Not IsPostBack Then afficheFormulaire()
    End Sub

[Page_Load] prosedürü bir POST istemcisinde yürütüldüğünde, formun tüm bileşenlerinin bir değeri olduğunu hatırlayalım: bu değer, varsa istemci tarafından gönderilen değer ya da [VIEWSTATE] sayesinde bileşenin önceki değeridir. Bu formda, tüm bileşenler [EnableViewState=true] özelliğine sahiptir. İsteği işlemeye başlamadan önce, uygulamanın düzgün bir şekilde başlatılabildiğinden emin oluruz. Aksi takdirde, [afficheErreurs] prosedürü ile [erreurs] görünümünü görüntüleriz. Bu ilk istekse (IsPostBack=false), [afficheFormulaire] ile [formulaire] görünümünü görüntüleriz.

[erreurs] görünümünü görüntüleyen prosedür şöyledir:


    Private Sub afficheErreurs(ByRef erreurs As ArrayList, ByRef lien As String)
        ' hata konteynerini görüntüler
        panelerreurs.Visible = True
        Dim i As Integer
        erreursHTML.Text = ""
        For i = 0 To erreurs.Count - 1
            erreursHTML.Text += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
        Next
        lnkForm1.Text = lien
        ' diğer kapsayıcılar gizlenir
        panelform.Visible = False
        panelsimulations.Visible = False
    End Sub

Bu prosedürün iki parametresi vardır:

  • [erreurs]'teki hata mesajları listesi
  • [lien]'teki bağlantı metni

Hata listesi için oluşturulacak HTML kodu, [erreursHTML] sabitine yerleştirilir. Bağlantı metni ise görünümün [LinkButton] nesnesinin [Text] özelliğine yerleştirilir.

[formulaire] görünümünü görüntüleyen prosedür şöyledir:


    Private Sub afficheFormulaire()
        ' form görüntülenir
        panelform.Visible = True
        ' diğer kapsayıcılar gizlenir
        panelerreurs.Visible = False
        panelsimulations.Visible = False
    End Sub

Bu prosedür, yalnızca [panelform] konteynerini görünür hale getirir. Bileşenler, gönderilen veya önceki değerleriyle (VIEWSTATE) görüntülenir.

Kullanıcı, [formulaire] görünümündeki [Calculer] düğmesine tıkladığında, POST'ten [main.aspx]'e bir geçiş yapılır. [Page_Load] prosedürü çalıştırılır, ardından [btnCalculer_Click] prosedürü çalıştırılır:


    Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
        ' girilen verilerin geçerliliği kontrol edilir
        Dim erreurs As ArrayList = checkData()
        ' Hata varsa bildirilir
        If erreurs.Count <> 0 Then
            ' hata sayfası görüntülenir
            afficheErreurs(erreurs, "Retour au formulaire")
            Exit Sub
        End If
        ' hata yoksa - vergi hesaplanır
        Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
        rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
        ' sonuç mevcut simülasyonlara eklenir
        Dim simulation() As String = New String() {CType(IIf(rdOui.Checked, "oui", "non"), String), _
         txtEnfants.Text.Trim, txtSalaire.Text.Trim, impot.ToString}
        ' sonuç mevcut simülasyonlara eklenir
        Dim simulations As ArrayList = CType(Session.Item("simulations"), ArrayList)
        simulations.Add(simulation)
        ' simülasyonlar oturuma ve bağlama eklenir
        Session.Item("simulations") = simulations
        ' sonuç sayfası görüntüleniyor
        afficheSimulations(simulations, "Retour au formulaire")
    End Sub

İşlem, [checkData] prosedürü ile form alanlarının geçerliliğini kontrol etmekle başlar; bu prosedür, [ArrayList] numaralı hata mesajları listesini döndürür. Liste boş değilse, [erreurs] görünümü görüntülenir ve işlem sonlandırılır. Girilen veriler geçerliyse, vergi tutarı, uygulamanın başlatılması sırasında uygulamada depolanmış olan [impot] türündeki nesne kullanılarak hesaplanır. Bu yeni simülasyon, daha önce yapılmış simülasyonlar listesine eklenir ve oturumda depolanır.

[CheckData] işlevi, verilerin geçerliliğini kontrol eder. Veriler geçerliyse boş olan bir [ArrayList] hata mesajları listesi döndürür:


    Private Function checkData() As ArrayList
        ' başlangıçta hata yok
        Dim erreurs As New ArrayList
        ' çocuk sayısı
        Try
            Dim nbEnfants As Integer = CType(txtEnfants.Text, Integer)
            If nbEnfants < 0 Then Throw New Exception
        Catch
            erreurs.Add("Le nombre d'enfants est incorrect")
        End Try
        ' maaş
        Try
            Dim salaire As Long = CType(txtSalaire.Text, Long)
            If salaire < 0 Then Throw New Exception
        Catch
            erreurs.Add("Le salaire annuel est incorrect")
        End Try
        ' hata listesi görüntüleniyor
        Return erreurs
    End Function

Son olarak, [simulations] görünümü aşağıdaki [afficheSimulations] prosedürü tarafından görüntülenir:


    Private Sub afficheSimulations(ByRef simulations As ArrayList, ByRef lien As String)
        ' simülasyonlar görünümünü görüntüler
        panelsimulations.Visible = True
        ' diğer konteynerler gizlenir
        panelerreurs.Visible = False
        panelform.Visible = False
        ' simülasyonlar görünümünün içeriği
        ' her simülasyon, 4 string elemanından oluşan bir dizidir
        Dim simulation() As String
        Dim i, j As Integer
        simulationsHTML.Text = ""
        For i = 0 To simulations.Count - 1
            simulation = CType(simulations(i), String())
            simulationsHTML.Text += "<tr>"
            For j = 0 To simulation.Length - 1
                simulationsHTML.Text += "<td>" + simulation(j) + "</td>"
            Next
            simulationsHTML.Text += "</tr>" + ControlChars.CrLf
        Next
        ' bağlantı
        lnkForm2.Text = lien
    End Sub

Bu prosedürün iki parametresi vardır:

  • [simulations]'teki simülasyon listesi
  • [lien]'teki bağlantı metni

Simülasyon listesi için oluşturulacak HTML kodu, [simulationsHTML] sabitine yerleştirilir. Bağlantı metni ise görünümdeki [LinkButton] nesnesinin [Text] özelliğine yerleştirilir.

Kullanıcı, [formulaire] görünümündeki [Effacer] düğmesine tıkladığında, [btnEffacer_click] prosedürü çalıştırılır (her zaman [Page_Load]'ten sonra):


    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
        ' boş formu görüntüler
        razForm()
        afficheFormulaire()
    End Sub

    Private Sub razForm()
        ' formu boşaltır
        rdOui.Checked = False
        rdNon.Checked = True
        txtEnfants.Text = ""
        txtSalaire.Text = ""
    End Sub

Yukarıdaki kod, açıklama gerektirmeyecek kadar basittir. Geriye, [erreurs] ve [simulations] görünümlerindeki bağlantılara yapılan tıklamaları yönetmek kalıyor:


    Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
        ' formu görüntüler
        afficheFormulaire()
    End Sub

    Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
        ' formu görüntüler
        afficheFormulaire()
    End Sub

Her iki prosedür de yalnızca [formulaire] görünümünü görüntülemekle yetinir. Bu görünümdeki alanların, ya kendileri için gönderilen değer ya da önceki değerlerini alacağını biliyoruz. Burada olduğu gibi, müşterinin POST'i form alanları için herhangi bir değer göndermediğinden, bu alanlar önceki değerlerine geri dönecektir. Dolayısıyla form, kullanıcı tarafından girilen değerlerle görüntülenir. Hatırlayacağınız üzere, sunucu bileşenleri içermeyen sürümde bu geri yükleme işlemini kendimiz gerçekleştirmiştik.

7.14.2.5. Testler

Uygulama için gerekli tüm dosyalar <application-path> klasörüne yerleştirilir:
[bin] klasörü, uygulama için gerekli olan [impot], [impotsData] ve [impotsOLEDB] sınıflarını içeren DLL dosyasını barındırır:

İsteyen okuyucular, yukarıdaki [impot.dll] dosyasının nasıl oluşturulacağının açıklandığı 5. bölümü tekrar okuyabilirler. Bu işlem tamamlandıktan sonra, Cassini sunucusu (<application-path>,/impots5) parametreleriyle başlatılır. Bir tarayıcıdan [http://impots5/main.aspx] URL'si istener:

Image

ACCESS adlı dosyayı [impots.mdb]'ten [impots1.mdb] olarak yeniden adlandırırsak, şu sayfa karşımıza çıkar:

Image

7.14.3. Örnek 3

Bu iki örnekle, sunucu bileşenleri kullanarak MVC mimarisine uygun web uygulamaları oluşturulabileceğini gösterdik. Son örnek, sunucu bileşenlerini kullanan çözümün standart HTML etiketlerini kullanan çözümden daha basit olduğunu göstermektedir. Her iki örneğimizde de aynı sayfa içinde birden fazla görünüm bulunan tek bir sayfa vardı. Form değerlerinin kendi kendilerine gönderilmesi sorun teşkil etmediği sürece, birden fazla sunucu tarafı ASP formu içeren bir MVC mimarisi oluşturulabilir. Menü içeren uygulamalarda bu durum çok sık görülür. Şu örneği ele alalım:

Image

Şimdiye kadar yazdığımız uygulamalara ait bağlantıları tek bir sayfada bir araya getirdik. Bu tür uygulamalar, MVC mimarisine çok uygundur. Tek fark, artık tek bir denetleyici yerine birden fazla denetleyici olmasıdır.

Image

[main.aspx] denetleyicisi, ana denetleyici rolünü üstlenir. Uygulamanın ana sayfasındaki bağlantılar tarafından çağrılan denetleyici budur. Bu denetleyici, tüm olası eylemler için ortak işlemleri gerçekleştirebilir ve ardından kullanılan bağlantıyla ilişkili özel eylemi yürütür. Daha sonra, eylemi yürütmekle görevli ikincil denetleyicilerden birine kontrolü devreder. Bu andan itibaren, iletişim istemci ile bu belirli denetleyici arasında gerçekleşir. Artık ana denetleyici [main.aspx] üzerinden işlem yapılmaz. Dolayısıyla, artık tüm istekleri filtreleyen tek bir denetleyicinin bulunduğu MVC çerçevesi içinde değiliz. Yukarıdaki denetleyicilerin her biri, daha önce anlattığımız tek bir sayfa içinde konteyner mekanizması sayesinde birden fazla görünüm sunabilir.

Müşteriye gönderilecek görünümleri seçen tek bir denetleyicinin artık olmaması bazı dezavantajlar da beraberinde getirir. Hata yönetimini örnek olarak ele alalım. Uygulama tarafından sunulan her eylem, bir hata görünümü görüntülemek zorunda kalabilir. Her bir [applix.aspx] denetleyicisinin kendine ait bir [erreurs] görünümü olacaktır, çünkü bu görünüm denetleyici sayfasının özel bir konteynerinden ibarettir. Tüm bireysel uygulamalar tarafından kullanılacak tek bir [erreurs] görünümüne sahip olmanın bir yolu yoktur. Nitekim, bu tür bir görünüm genellikle hatalı forma geri dönme bağlantısı içerir ve kullanıcının hatalarını düzeltebilmesi için formun, onaylandığı duruma geri yüklenmesi gerekir. Bu geri yükleme işlemi, farklı denetleyiciler arasında çalışmayan [VIEWSTATE] mekanizması aracılığıyla gerçekleştirilir. Uygulamalar farklı kişiler tarafından geliştirilirse, kullanıcının seçtiği eyleme bağlı olarak farklı görünümde hata sayfaları ortaya çıkma riski vardır ve bu da genel uygulamanın bütünlüğünü bozar. Biraz sonra göreceğimiz gibi, ASP.NET, paylaşılan görünümle ilgili bu özel soruna bir çözüm sunar. Bu çözüm, kendimizin geliştireceği yeni bir sunucu bileşeni haline getirilebilir. Genel uygulamanın bütünlüğünü sağlamak için bu bileşeni farklı uygulamalarda kullanmak yeterlidir. Yönetilmesi daha zor olan sorun ise eylemlerin sırasıdır. Tüm istekler tek bir denetleyiciden geçtiğinde, bu denetleyici istenen eylemin bir öncekiyle uyumlu olup olmadığını kontrol edebilir. Bu kontrol kodu tek bir yerde bulunur. Burada ise bu kodu farklı denetleyicilere dağıtmak gerekecek ve bu da genel uygulamanın bakımını zorlaştıracaktır.

Yukarıdaki uygulamamıza geri dönelim. Bu uygulamanın giriş sayfası, klasik bir HTML sayfasıdır:

<html>
    <head>
        <TITLE>Composants ASP Serveur</TITLE>
        <meta name="pragma" content="no-cache">
    </head>
    <frameset rows="130,*" frameborder="0">
        <frame name="banner" src="bandeau.htm" scrolling="no">
        <frameset cols="200,*">
            <frame name="contents" src="options.htm">
            <frame name="main" src="main.htm">
        </frameset>
        <noframes>
            <p id="p1">
                Ce jeu de frames HTML affiche plusieurs pages Web. Pour afficher ce jeu de 
                frames, utilisez un navigateur Web qui prend en charge HTML 4.0 et version 
                ultérieure.
            </p>
        </noframes>
    </frameset>
</html>

Bu ana sayfa, banner, contents ve main olarak adlandırılan üç çerçeveden oluşur:

[banner] çerçevesine yerleştirilen [bandeau.htm] sayfası şöyledir:

Image

HTML kodunun içeriği şöyledir:


<html>
    <head>
        <META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE" />
        <title>bandeau</title>
    </head>
    <body>
        <P>
            <TABLE>
                <TR>
                    <TD><IMG alt="logo université d'angers" src="univ01.gif"></TD>
                    <TD>Composants serveurs ASP</TD>
                </TR>
            </TABLE>
        </P>
        <HR>
    </body>
</html>

[options.htm] sayfası, [contents] başlığına yerleştirilmiştir. Bu, bir dizi bağlantıdan oluşur:


<html>
    <head>
        <meta http-equiv="pragma" content="no-cache" />
        <title>options</title>
    </head>
    <body bgcolor="Gold">
        <ul>
            <li>
                <a href="main.aspx?action=label" 
                 target="main">Label</a>
            <li>
                <a href="main.aspx?action=button" 
                 target="main">Button</a>
            <li>
                <a href="main.aspx?action=textbox1" 
                 target="main">TextBox-1</a></li>
            <li>
                <a href="main.aspx?action=textbox2" 
                 target="main">TextBox-2</a></li>
            <li>
                <a href="main.aspx?action=dropdownlist" 
                 target="main">DropDownList</a></li>
            <li>
                <a href="main.aspx?action=listbox" 
                 target="main">ListBox</a></li>
            <li>
                <a href="main.aspx?action=casesacocher" 
                  target="main">CheckBox</a> et<br>
                RadioButton</li>
            <li>
                <a href="main.aspx?action=listecasesacocher" 
                  target="main">CheckBoxList</a> et<br>
                RadioButtonList</a></li>
            <li>
                <a href="main.aspx?action=panel" 
                  target="main">Panel</a></li>
        </ul>
    </body>
</html>

Farklı bağlantılar, gerçekleştirilecek eylemi belirten [action] parametresiyle birlikte, hepsi [main.aspx] ana denetleyicisine yönlendirilmektedir. Bağlantıların hedeflerinin [main] çerçeve içinde görüntülenmesi istenmektedir (target="main").

[main] çerçevesinde görüntülenen ilk sayfa [main.htm]'tir:


<html>
    <head>
        <title>main</title>
    </head>
    <body>
        <P>Choisissez une option pour tester découvrir un type de composant serveur...</P>
    </body>
</html>

[main.aspx, main.aspx.vb] ana denetleyicisi şöyledir:

[main.aspx]

<%@ page src="main.aspx.vb" inherits="main" autoeventwireup="false" %>

[main.aspx.vb]

Public Class main

Inherits System.Web.UI.Page

Özel Alt Program Page_Load(ByVal gönderici As System.Object, ByVal e As System.EventArgs) MyBase.Load tanıtıcıları

' yapılacak eylem alınır

Dim action As String

If Request.QueryString("action") Is Nothing Then

action = "label"

Else

action = Request.QueryString("action").ToString.ToLower

End If

' eylem gerçekleştirilir

Select Case eylem

Case "label"

Server.Transfer("form2.aspx")

Case "button"

Server.Transfer("form3.aspx")

"textbox1" durumu

Server.Transfer("form4.aspx")

"textbox2" durumu

Server.Transfer("form5.aspx")

"dropdownlist" durumu

Server.Transfer("form6.aspx")

"listbox" kutusu

Server.Transfer("form7.aspx")

"onay kutusu" kutusu

Server.Transfer("form8.aspx")

"onay kutuları listesi" kutusu

Server.Transfer("form8b.aspx")

"panel" kutusu

Server.Transfer("form9.aspx")

Case Else

Server.Transfer("form2.aspx")

End Select

End Sub

End Class

Denetleyicimiz basittir. [action] parametresinin değerine göre, isteğin işlenmesini uygun sayfaya aktarır. Bağlantılar içeren bir HTML sayfasına kıyasla herhangi bir katma değer sağlamaz. Bununla birlikte, bir kimlik doğrulama sayfası eklenmesi durumunda bu denetleyicinin yararı ortaya çıkacaktır. Kullanıcının uygulamalara erişmek için kimlik doğrulaması (kullanıcı adı, şifre) yapması gerekiyorsa, [main.aspx] denetleyicisi bu kimlik doğrulamasının yapıldığını kontrol etmek için uygun bir yer olacaktır.