Skip to content

6. Olay Yönetimi

Bir önceki bölümde bileşenlerle ilgili olay kavramını ele almıştık. Şimdi kendi sınıflarımızda nasıl olaylar oluşturacağımızı göreceğiz. Bu zor bir konudur ve yeni başlayan geliştiricilerin ilgisini çekmeyecektir; bu nedenle yeni başlayan geliştiricilerin doğrudan bir sonraki bölüme geçmeleri tavsiye edilir.

6.1. Delegate nesneleri

Şu komut:

    Delegate Function opération(ByVal n1 As Integer, ByVal n2 As Integer) As Integer

komutu, opération adlı bir türü tanımlar; bu tür, aslında iki tamsayı alan ve bir tamsayı döndüren bir işlev prototipidir. opération'i bir işlev prototipi tanımı yapan, delegate anahtar sözcüğüdür. [opération] türü, bir değişkene şu şekilde atanabilir:


        Dim op As New opération(AddressOf [fonction])

[délégué] türündeki bir değişken, bir nesne olarak oluşturulur. Oluşturucunun parametresi, delege örneğiyle ilişkili işlevdir. VB'te bu işlev, AddressOf işlevi biçiminde verilir; burada [fonction] işlevin adıdır. Bir delege örneği oluşturulduktan sonra, bir işlev olarak kullanılabilir:


        ' delege işlevi çalıştırılıyor
        Dim n As Integer = op(4, 7)

[opération] delege, [integer] türünde iki parametre alacak ve aynı türde bir sonuç döndürecek şekilde tanımlanmıştır. Dolayısıyla, yukarıdaki [op] örneği bu tür bir işlev olarak kullanılır. Aşağıdaki örneği ele alalım:


' delege edilmiş işlevler
Imports System

Public Class delegate1
    ' fonksiyon prototipi tanımı
    ' 2 tamsayı parametre alır ve bir tamsayı döndürür
    Delegate Function opération(ByVal n1 As Integer, ByVal n2 As Integer) As Integer

    ' prototipe karşılık gelen iki örnek yöntemi
    ' ekle
    Public Function ajouter(ByVal n1 As Integer, ByVal n2 As Integer) As Integer
        Console.Out.WriteLine(("ajouter(" & n1 & "," & n2 & ")"))
        Return n1 + n2
    End Function

    ' çıkarma
    Public Function soustraire(ByVal n1 As Integer, ByVal n2 As Integer) As Integer
        Console.Out.WriteLine(("soustraire(" & n1 & "," & n2 & ")"))
        Return n1 - n2
    End Function

    ' prototipe karşılık gelen bir statik yöntem
    Public Shared Function augmenter(ByVal n1 As Integer, ByVal n2 As Integer) As Integer
        Console.Out.WriteLine(("augmenter(" & n1 & "," & n2 & ")"))
        Return n1 + 2 * n2
    End Function

    ' test programı
    Public Shared Sub Main()
        ' fonksiyonları kaydetmek için bir işlem türü nesnesi tanımlanır
        ' "artır" statik fonksiyonu kaydedilir
        Dim op As New opération(AddressOf delegate1.augmenter)
        ' delege çalıştırılıyor
        Dim n As Integer = op(4, 7)
        Console.Out.WriteLine(("n=" & n))
        ' class1 türünde bir c1 nesnesi oluşturulur
        Dim c1 As New delegate1
        ' c1 nesnesinin "ekle" yöntemini delegeye kaydedilir
        op = New delegate1.opération(AddressOf c1.ajouter)
        ' delege nesnesinin çalıştırılması
        n = op(2, 3)
        Console.Out.WriteLine(("n=" & n))
        ' c1'in "çıkarma" yöntemini delegeye kaydediliyor
        op = New delegate1.opération(AddressOf c1.soustraire)
        n = op(2, 3)
        Console.Out.WriteLine(("n=" & n))
    End Sub
End Class

Çalıştırma sonuçları şöyledir:

augmenter(4,7)
n=18
ajouter(2,3)
n=5
soustraire(2,3)
n=-1

6.2. Olay yönetimi

delegate türündeki bir nesne ne işe yarar?

Aşağıdaki örnekte göreceğimiz gibi, bu nesne esas olarak olay yönetiminde kullanılır. Bir C1 sınıfı, evti olaylarını oluşturabilir. Bir evti olayı sırasında, C1 türündeki bir nesne, delegate türündeki bir evtiDéclenché nesnesinin yürütülmesini başlatır. Böylece, evtiDéclenché delegasyon nesnesinde kayıtlı tüm işlevler yürütülecektir. C1 nesnesini kullanan bir C2 nesnesi, C1 nesnesinde evti olayının meydana geldiği konusunda bilgilendirilmek isterse, C1 nesnesinin vekil nesnesi olan C1.evtiDéclenché'e kendi C2.f yöntemlerinden birini kaydedecektir; böyleceC1 nesnesinde evti olayı her gerçekleştiğinde C2.f yöntemi çalıştırılsın. C1.evtiDéclenché delege nesnesi birden fazla işlev kaydedebileceğinden, farklı Ci nesneleri, C1 üzerindeki evti olayından haberdar olmak için C1.evtiDéclenché delege nesnesine kaydolabilir.

6.2.1. Bir olayın bildirilmesi

Bir olay şu şekilde bildirilir (1):


Delegate Sub proc(liste d'arguments)
Public Event événement as proc

ya da (2)


Public Event événement(liste d'arguments)

Bir veriyi olay olarak tanımlayan anahtar kelime [Event]'tir. Olayla, bu olayı işleyecek işleyicilerin sahip olması gereken imza ilişkilendirilir. Bu imza, bir delege aracılığıyla (yöntem 1) veya doğrudan (yöntem 2) tanımlanabilir.

6.2.2. Bir olayın işleyicilerini tanımlama

[RaiseEvent] komutuyla bir olay tetiklendiğinde, bu olayın işlenmesi gerekir. Olayları işlemekle görevli prosedürlere olay işleyicileri denir. Bir [Event] nesnesi oluşturulduğunda, yalnızca olay işleyicilerinin imzası bildirilir. Bu imza, olayla ilişkilendirilmiş [delegate] nesnesinin imzasını taşır. Bu işlem tamamlandıktan sonra, olaya işleyiciler ilişkilendirilebilir. Bu işleyiciler, olayla ilişkili [delegate] nesnesiyle aynı imzaya sahip olmalıdır. Bir olay işleyicisini bir olaya ilişkilendirmek için, aşağıdaki sözdizimine sahip [AddHandler] komutu kullanılır:

AddHandler event, AddressOf eventhandler
  • event: yeni bir olay işleyicisinin ilişkilendirileceği olay değişkeni
  • eventhandler: olay işleyicisinin adı - olayla ilişkilendirilen [délégué] komutuyla aynı imzaya sahip olmalıdır

Bir olaya istediğiniz kadar işleyici atayabilirsiniz. Bunlar, atandıkları olay tetiklendiğinde hepsi çalıştırılacaktır.

6.2.3. Bir olayı tetikleme

Program yoluyla bir olayı tetiklemek için [RaiseEvent] komutu kullanılır:

RaiseEvent eventname[( argumentlist )]
  • eventname: olay değişkeni (Event anahtar sözcüğüyle tanımlanır)
  • argumentlist: olaya atanan delegenin argümanları.

AddHandler komutuyla olaya ilişkilendirilmiş tüm işleyiciler çağrılacaktır. Bu işleyiciler, olayın imzasında tanımlanan parametreleri parametre olarak alacaktır.

6.2.4. Bir örnek

Aşağıdaki örneği ele alalım:


'olay yönetimi
Imports System

Public Class myEventArgs
    Inherits EventArgs
    ' bir olayın sınıfı
    ' özellik
    Private _saisie As String

    ' yapıcı
    Public Sub New(ByVal saisie As String)
        _saisie = saisie
    End Sub

    ' salt okunur giriş özelliği
    Public Overrides Function ToString() As String
        Return _saisie
    End Function
End Class

Public Class émetteur
    ' bir olayın gönderen sınıfı
    ' özellik
    Private _nom As String    ' nom de l'émetteur

    ' yapıcı
    Public Sub New(ByVal nom As String)
        _nom = nom
    End Sub

    ' ToString
    Public Overrides Function ToString() As String
        Return _nom
    End Function

    ' olayı işleyen fonksiyonların prototipi
    Delegate Sub _evtHandler(ByVal sender As Object, ByVal evt As myEventArgs)

    ' olay işleyicileri havuzu
    Public Event evtHandler As _evtHandler

    ' bir olayın yayınlanmasını talep etme yöntemi
    Public Sub envoyerEvt(ByVal evt As myEventArgs)
        ' tüm abonelere bildirim gönderilir
        ' olay buradan geliyormuş gibi davranılır
        RaiseEvent evtHandler(Me, evt)
    End Sub
End Class

' bir olay işleme sınıfı
Public Class souscripteur
    ' özellik
    Private nom As String    ' nom du souscripteur
    Private sender As émetteur    ' l'émetteur des évts

    ' yapıcı
    Public Sub New(ByVal nom As String, ByVal e As émetteur)
        ' abone adını not ediyoruz
        Me.nom = nom
        ' ve olayların yayıncısını
        Me.sender = e
        ' e olay yayıncısından olayları almak için kaydolun
        AddHandler e.evtHandler, AddressOf traitementEvt
    End Sub

    ' olay yöneticisi
    Public Sub traitementEvt(ByVal sender As Object, ByVal evt As myEventArgs)
        ' olay görüntüleme
        Console.Out.WriteLine(("L'objet [" + sender.ToString + "] a signalé la saisie erronée [" + evt.ToString + "] au souscripteur [" + nom + "]"))
    End Sub
End Class

' bir test programı
Public Class test
    Public Shared Sub Main()
        ' bir olay vericisinin oluşturulması
        Dim émetteur1 As New émetteur("émetteur1")
        ' abone tablosu oluşturma
        ' yayıncı1 tarafından yayınlanan olaylar için
        Dim souscripteurs() As souscripteur = {New souscripteur("s1", émetteur1), New souscripteur("s2", émetteur1)}
        ' klavyeden bir dizi tamsayı okunur
        ' Bir tanesi hatalı olur olmaz bir olay yayınlanır
        Console.Out.Write("Nombre entier (rien pour arrêter) : ")
        Dim saisie As String = Console.In.ReadLine().Trim()
        ' girdilen satır boş olmadığı sürece
        While saisie <> ""
            ' Girilen değer bir tamsayı mı?
            Try
                Dim n As Integer = Integer.Parse(saisie)
            Catch
                ' bu bir tamsayı değil
                ' herkese uyarı verilir
                émetteur1.envoyerEvt(New myEventArgs(saisie))
            End Try
            ' herkese uyarı verilir
            ' yeni giriş
            Console.Out.Write("Nombre entier (rien pour arrêter) : ")
            saisie = Console.In.ReadLine().Trim()
        End While
        ' son
        Environment.Exit(0)
    End Sub
End Class

Yukarıdaki kod oldukça karmaşıktır. Bunu ayrıntılı olarak inceleyelim. Bir olay yönetiminde, söz konusu olaylara ilgi duyduğunu beyan eden abonelere olay ayrıntılarını (EventArgs) gönderen bir olay yayıncısı (sender) vardır. Burada olayları yayınlayan sınıf şöyledir:


Public Class émetteur
    ' bir olayın gönderen sınıfı
    ' özellik
    Private _nom As String    ' nom de l'émetteur

    ' oluşturucu
    Public Sub New(ByVal nom As String)
        _nom = nom
    End Sub

    ' ToString
    Public Overrides Function ToString() As String
        Return _nom
    End Function

    ' olayı işleyen fonksiyonların prototipi
    Delegate Sub _evtHandler(ByVal sender As Object, ByVal evt As myEventArgs)

    ' olay işleyicileri havuzu
    Public Event evtHandler As _evtHandler

    ' bir olayın yayınlanmasını talep etme yöntemi
    Public Sub envoyerEvt(ByVal evt As myEventArgs)
        ' tüm abonelere bildirim gönderilir
        ' olay buradan geliyormuş gibi davranılır
        RaiseEvent evtHandler(Me, evt)
    End Sub
End Class

Her émetteur nesnesinin, yapısal olarak belirlenmiş bir nom'i vardır. ToString yöntemi, bir émetteur nesnesini string,'e dönüştürürken bu nesnenin adının alınacağı şekilde yeniden tanımlanmıştır. Sınıf, bir olay tanımlar:


        ' olayı işleyen fonksiyonların prototipi
        Delegate Sub _evtHandler(ByVal sender As Object, ByVal evt As myEventArgs)

        ' olay
        Public Event evtHandler As _evtHandler

Bir olay işleme fonksiyonunun ilk argümanı, olayı tetikleyen nesne olacaktır. İkinci argüman, olayla ilgili ayrıntıları veren ve daha sonra tekrar ele alacağımız myEventArgs türünde bir nesne olacaktır. Bir émetteur nesnesinin dışından bir olayı tetikleyebilmek için, sınıfa envoyerEvt yöntemini ekliyoruz:


    ' bir olayın yayınlanmasını talep etme yöntemi
    Public Sub envoyerEvt(ByVal evt As myEventArgs)
        ' tüm abonelere bildirim gönderilir
        ' olay buradan geliyormuş gibi davranılır
        RaiseEvent evtHandler(Me, evt)
    End Sub

émetteur sınıfı tarafından tetiklenecek olayların türünü tanımlamamız gerekiyor. Bunun için myEventArgs sınıfını tanımladık:


Public Class myEventArgs
    ' bir olayın sınıfı
    ' özellik
    Private _saisie As String

    ' yapıcı
    Public Sub New(ByVal saisie As String)
        _saisie = saisie
    End Sub

    ' salt okunur giriş özelliği
    Public Overrides Function ToString() As String
        Return _saisie
    End Function
End Class

Bizi ilgilendiren olaylar, klavyeden yapılan hatalı girişlerdir. Bir kullanıcıdan klavyeden tamsayılar girmesini isteyeceğiz ve tamsayı olmayan bir dize girdiğinde bir olay tetiklenecektir. Olayın detayı olarak, hatalı girişi belirtmekle yetineceğiz. Sınıfın _saisie özniteliğinin amacı budur. Dolayısıyla, hatalı girişi parametre olarak alan bir myEventArgs nesnesi oluşturulur. Ayrıca, bir myEventArgs nesnesini dizgeye dönüştürdüğümüzde _saisie özniteliğini elde edebilmek için ToString yöntemini yeniden tanımlıyoruz.

Olayların kaynağını ve kaynağın yaydığı olay türlerini tanımladık. Ardından, bu olaylarla ilgilenen abone türlerini tanımlıyoruz.


    ' olay işleme sınıfı
    Public Class souscripteur
        ' özellik
        Private nom As String     ' nom du souscripteur
        Private sender As émetteur     ' l'émetteur des évts

        ' oluşturucu
        Public Sub New(ByVal nom As String, ByVal e As émetteur)
            ' abone adı kaydedilir
            Me.nom = nom
            ' ve olayların yayıncısını
            Me.sender = e
            ' e olay vericisinin olaylarını almak için kaydolun
            AddHandler e.evtHandler, AddressOf traitementEvt
        End Sub

        ' olay yöneticisi
        Public Sub traitementEvt(ByVal sender As Object, ByVal evt As myEventArgs)
            ' olay görüntüleme
            Console.Out.WriteLine(("L'objet [" + sender.ToString + "] a signalé la saisie erronée [" + evt.ToString + "] au souscripteur [" + nom + "]"))
        End Sub
    End Class

Bir abone, iki parametre ile tanımlanacaktır: adı (nom özniteliği) ve olaylarını işlemek istediği émetteur nesnesi (sender özniteliği). Bu iki parametre, nesnenin oluşturucusuna aktarılacaktır. Aynı oluşturma işlemi sırasında, abone yayıncının olaylarına abone olur:


            ' yayıncının olaylarını almak için kayıt oluruz
            AddHandler e.evtHandler, AddressOf traitementEvt

Yayına kaydedilen işlev traitementEvt'tir. souscripteur sınıfının bu yöntemi, aldığı iki argümanı (sender, evt) ve alıcının adını (nom) görüntüler. Oluşturulan olayların türü, bu olayların göndereninin türü ve abonelerin türü tanımlanmıştır. Artık bunları uygulamaya koymamız gerekiyor:


    ' bir test programı
    Public Class test
        Public Shared Sub Main()
            ' olay vericisi oluşturma
            Dim émetteur1 As New émetteur("émetteur1")
            ' abone tablosu oluşturma
            ' yayıncı1 tarafından yayınlanan olaylar için
            Dim souscripteurs() As souscripteur = {New souscripteur("s1", émetteur1), New souscripteur("s2", émetteur1)}
            ' klavyeden bir dizi tamsayı okunur
            ' Bir tanesi hatalı olur olmaz bir olay yayınlanır
            Console.Out.Write("Nombre entier (rien pour arrêter) : ")
            Dim saisie As String = Console.In.ReadLine().Trim()
            ' girdilen satır boş olmadığı sürece
            While saisie <> ""
                ' Girilen değer bir tamsayı mı?
                Try
                    Dim n As Integer = Integer.Parse(saisie)
                Catch
                    ' bu bir tamsayı değil
                    ' herkese uyarı verilir
                    émetteur1.envoyerEvt(New myEventArgs(saisie))
                End Try
                ' herkese uyarı verilir
                ' yeni giriş
                Console.Out.Write("Nombre entier (rien pour arrêter) : ")
                saisie = Console.In.ReadLine().Trim()
            End While
            ' son
            Environment.Exit(0)
        End Sub

Bir émetteur nesnesi oluşturuyoruz:


         ' bir olay yayınlayıcısı oluşturuluyor
        Dim émetteur1 As New émetteur("émetteur1")

émetteur1 nesnesi tarafından yayınlanan olaylar için iki abone içeren bir tablo oluşturuyoruz:


         ' abone tablosu oluşturma
         ' yayıncı1 tarafından yayınlanan olaylar için
        Dim souscripteurs() As souscripteur = {New souscripteur("s1", émetteur1), New souscripteur("s2", émetteur1)}

Kullanıcıdan klavyeyle tamsayılar girmesini istiyoruz. Hatalı bir giriş yapıldığında, émetteur1 nesnesinden abonelerine bir olay göndermesini istiyoruz:


                 ' herkese bildirim gönderilir
                émetteur1.envoyerEvt(New myEventArgs(saisie))

Gönderilen olay, myEventArgs türündedir ve hatalı girişi içerir. Her iki abone de bu olayı almalı ve bildirmelidir. Aşağıdaki çalıştırma örneği bunu göstermektedir.

dos>evt1
Nombre entier (rien pour arrêter) : 4
Nombre entier (rien pour arrêter) : a
L'objet [émetteur1] a signalé la saisie erronée [a] au souscripteur [s1]
L'objet [émetteur1] a signalé la saisie erronée [a] au souscripteur [s2]
Nombre entier (rien pour arrêter) : 1.6
L'objet [émetteur1] a signalé la saisie erronée [1.6] au souscripteur [s1]
L'objet [émetteur1] a signalé la saisie erronée [1.6] au souscripteur [s2]
Nombre entier (rien pour arrêter) :