VB 2008 - neprovedení standardní procedury při události objektu   zodpovězená otázka

VB.NET, Algoritmy

Všechny kdo chtějí pomoci zdravím a děkuji. Mám následující problém, se kterým bych potřeboval pomoci.

Téma má vztah k Addhandler tzn. k delegátům a také k dědičnosti. Možná, nechci strašit :), budeme muset i zajít do knihoven API.

Představte si následující situaci viz. jednoduchý kód:

 Private Volba As Boolean
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        'Jelikož chci aby moje vlastní vytvořená proceduru KdyzZjistimHodnotuNaFalseTakPracuju proběhla první
        'tzn. před defaultní procedurou události objektu musím nejdřiv tuto "defaultni proceduru odstranit"
        'a pak ji znovu připojit

     
        RemoveHandler Button1.Click, AddressOf Button1_Click

        AddHandler Button1.Click, New System.EventHandler(AddressOf KdyzZjistimHodnotuNaFalseTakPracuju)
        AddHandler Button1.Click, New System.EventHandler(AddressOf Button1_Click)

    End Sub


    Private Sub KdyzZjistimHodnotuNaFalseTakPracuju(ByVal sender As System.Object, ByVal e As System.EventArgs)

        If Volba = True Then
            'Kód, který nařídí neprovedení události  Button1_Click

            'Tady prosím tvořte :) Děkuji

        End If
        MsgBox("Tuto proceduru chci provádět vždy, ale nesmí se jedná o defaultní" & _
               " proceduru objektu k dané události, jelikož bude vždy vytvořena v modulu")

    End Sub
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MsgBox("Cíl projektu je, že procedura: KdyzZjistimHodnotuNaFalseTakPracuju" & _
                 " zajistí, že se na základě určité volby neprovede procedura Button1_Click," & _
                 "  která je delegována na stejný objekt a stejnou událost objektu")


    End Sub

Ještě maličkost vytvořil jsem v kódu místo pro vaše řešení. Jelikož celý můj projekt je složitější zkuste se vejít do tohoto místa a jinam kód nevkládat. Ještě jednou dík.

PS: poznámky a funkce jsou napsány přímo v kódu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Já skutečně nechápu proč za každou cenu chcete v tomto případě zcela a naprosto zbytečně napojovat dvě různé metody na událost Click??? Proč to vše neošetřit pouze v metodě Button1_Click?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Důvodem je to, že chci přiřadit k určitým controls předem definovanou událost, abych ji nemusel na každém formu psát do každého prvku a přitom mi zůstala určitá variabilita každého formu, když zadám kód do defuáltní události. Problém je v tom, že někdy potřebuju defaultní událost daného objektu vyřadit - neprovádět, ale pouze provést tu předem definovanou událost.

Děkuji za reakci.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Zaprvé - když už stejně metodu Button1_Click mapujete na událost tlačítka pomocí AddHandler poté, co ji smažete, je zbytečné, aby u metody Button1_Click bylo klíčové slovo Handles. Ale to je jedno

Jinak ideální řešení je udělat to přes dědičnost. Prostě si udělat třídu poděděnou z Button a přepsat metodu OnClick. Do ní dejte řádek volající danou metodu (třeba si do tlačítka přidejte událost BeforeClick a tu tam zavolejte), a pak nezapomeňte zavolat Base.OnClick(e), aby se nerozbila funkcionalita tlačítka a fungovalo klikání.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Tohle je dobré řešení, ale má to jeden háček. Musel bych vytvářet objekty odvozené z třídy.

Jestli jsem správně pochopil váš návrh řešení, tak by to mělo vypadat nějak takhle:

Např.:

Public Class MujNovyButton
        Inherits System.Windows.Forms.Button
        Dim Volba As Boolean
        Protected Overrides Sub OnClick(ByVal e As EventArgs)
            If Volba = True Then
                MyBase.OnClick(e)
            Else
                'Udela neco jineho
            End If
        End Sub
    End Class

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
       Dim ctrl As New MujNovyButton
        With ctrl
            .Location = New System.Drawing.Point(0, 0)
            .Name = "clk_Zkouska"
            .Size = New System.Drawing.Size(200, 69)
        End With
        sender.Controls.Add(ctrl)
End Sub

Ja bych, ale potřeboval abych nemusel vytvářet prvky z odvozené třídy, protože výhoda by spočívala v tom, že si v design módu vložím textboxy, button, listview apod. a ke všem si po zavolání proceduru v modulu (s parametrem ukazující na form) přiřadí automatické akce ke controls daného formu, které jsem si definoval, že jsou pro celou alikaci standardní.

Další nevyhodou je to, že musím vytvořit třídy pro textboxy, button, listview apod. Ideální řešení je to, že si v procedůře modulu prohlédnu všechny controls formu a ke všem prvků bez ohledu na typ přiřadím mojí událost onClick se specifikacemi, které jsem v zadání popsal.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No tak to snad není problém v metodách ButtonX_Click volat nějakou společnou funkci a v případě potřeby do této metody (ButtonX_Click) připsat další kód ne? Proč to vymýšlíte tak složitě?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak a mám to vyřešený - šel jsem na to zbytečně složitě, protože je to hrozně easy řešení. Všem děkuji a za odměnu přikládám jednoduchou ukázku:

Vše do formu pro ukázku si vložte na form dva buttony button1 a button2 (button2 mění hodnotu, která to celé definuje)

   Dim ChciDefaultni As Byte
    Private Sub PokazdeClick(ByVal sender As System.Object, ByVal e As System.EventArgs) ' Handles Button1.Click

        MsgBox("Za běhu")
        If ChciDefaultni = 1 Then
            MsgBox("Teď nechci provést defaultní událost")

        Else
            MsgBox("Teď musím provést také defaultní událost")
            Button1_Click(sender, e)

            'InvokeOnClick(Button1, e) 'Nepouzivat vytvoril by se nekonecny cyklus (opakoval by se click)
        End If

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MsgBox("Původně v objektu")
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Select Case ChciDefaultni
            Case Is = 1
                ChciDefaultni = 0
            Case Else
                ChciDefaultni = 1
        End Select
    End Sub
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        RemoveHandler Button1.Click, AddressOf Button1_Click
        AddHandler Button1.Click, New System.EventHandler(AddressOf PokazdeClick)

    End Sub

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Radime,

gratuluji k úspěchu, jenom bych přidal drobnou radu pro příště pro snadnější získávání informací z diskuse:

V prvé řadě, nevidím výhodu v otevírání více vláken na stejné téma. (předpokládám, že otázka na stejný problém, kterou jsi připojil o den dříve do vlákna "AddHandler" ( http://www.vbnet.cz/forum-tema--1954-add... ) je od Tebe (máš velice specifický požadavek, tak by to musela být obrovská náhoda, kdybyste se na totéž ve stejném termínu ptali dva. Jednak to diskusi dost znepřehledňuje, pisatel pak neví, do kterého vlákna Ti odpovědět apod.

Pokud by ten o den starší dotaz přece jenom nebyl od tebe, bylo by dobré před položením dotazu dát alespoň základní dotaz (hledání), zdali se něco podobného již neřešilo.

Problém je mimo jiné i v tom, že možná někteří, kteří se Ti i v tomto vlákně snažili pomoci netušili, kam svým dotazem míříš, protože řešení, ke kterému jsi nakonec dospěl, je totožné s kódem, který jsem Ti v tom prvním vlákně navrhnul ještě předevčírem, takže každý zákonitě z toho musel usoudit, že to není to, co hledáš.

Jina k Tvému kódu pár drobností:

Nebylo by lépe jako přepínač použít hodnotu Boolean místo Byte a namísto komplikované struktury select-Case zjednodušit metodu Button2_click třeba takhle:

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        ChciDefaultni = not ChciDefaultni
End Sub

Stejně tak si myslím, že i to přidání Handleru ve zkrácené notaci vypadá v kódu přehledněji (ač to funkčně provádí naprosto totéž):

AddHandler Button1.Click, AddressOf PokazdeClick

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dík za zlepšení určitě Byte je na tom s pamětí lépe než boolean, ale pro zkoušení jsem to nepotřeboval.

Jinak diskuzi tady na téma AddHandler jsem četl, ale problém se zkomplikoval tím, že se nejednalo o proceduru mnou připojenou, ale defaultní a proto moje úvahy o postupu šli směrem dědičnost přepisování apod. Nakonec jsem se vrátil k úplným základům a výsledek může vypadat podobně, ale rozhodně není.

Rozhodně to stojí za zapamatování, když to člověk bude potřebovat. Jinak tento problém pokračuje v novém tématu a to pod názvem Dynamický AddressOF.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback