BindEvent() And other
Posted: Sun Jun 14, 2020 2:47 am
I had send an email to you.robert wrote:xinjie,
Maybe you can send me a private email to we can discuss this ?
Robert
I had send an email to you.robert wrote:xinjie,
Maybe you can send me a private email to we can discuss this ?
Robert
Hi Robert,robert wrote: The BindEvent function is a runtime function that allows you to bind a function (method) to an event.
In X# we do that at compile time, just like in C# and VB. For example for a Form object you can bind an event with the += syntax:The Form_Loaded method must have the right parameters (the compiler will check this)Code: Select all
oForm:Loaded += Form_Loaded
And to remove an event handler you write the same code with the "-=" syntax,
In theory you can also do this in code (and we could therefore implement the BindEvents() function) but that is simply not the right solution.
Whipped up a VERY basic sample of the approach to "retrofit" a timing log to specific object.method() calls, as this is more "against Dotnet thinking" compared to having a special method linking specific delegates in the init of interesting classes.robert wrote:We may be able to emulate this behavior, but to properly do so we need an example that shows what you describe.
Are you saying that you want to have one method as "handler" for all events, with different parameters depending on the event that was called ?
We can probably do that by creating a method "on the fly" that then does a Clipper Calling convention call to your code.
Can you provide us with an example ?
Code: Select all
* BindEvent Logger
clea
*--- tiny stuff injected in app code
private poLog
poLog = createobject("Logger_Base")
***************************************************************
*-- this would usually be table based, to switch several dozen timers on/off with single SQL on table
= Check_Instance("Worker_Fast", "Do_Job")
= Check_Instance("Worker_Base", "Do_Wrk, Do_Val, Do_Sav")
= Check_Instance("Worker_Fast", "Do_Wrk, Do_Job")
= Check_Instance("Worker_Slow", "Do_Wrk, Do_Val, Do_Sav, Do_Job")
= Check_Instance("Worker_Sloppy", "Do_Wrk, Do_Val, Do_Sav, Do_Job")
function Check_Instance(tcObj, tcWatchList)
local loWork
loWork = createobject(m.tcObj)
= poLog.Wrap_List(m.loWork, m.tcWatchList)
loWork.Do_Job()
***************************************************************
* logger classes have more capabilities only example of "static external code"
define class EvWrapper as custom
function Wrap_List(toSource, tcMethodCSV, toHandler, tcDelegate))
local laMethods[1], lnRun
for lnRun = 1 to alines(laMethods, m.tcMethodCSV, 5, ",")
= this.Wrap_Both(m.toSource, laMethods[m.lnRun], m.toHandler, m.tcDelegate)
next
function Wrap_Both(toSource, tcEvent, toHandler, tcDelegate)
local loHandler, lcDelegate
*-- make last 2 parameters optional via defaults
loHandler = iif(vartype(m.toHandler)=="O", m.toHandler, this)
lcDelegate = iif(vartype(m.toHandler)=="C", m.tcDelegate, "Log")
= bindevent(m.toSource, m.tcEvent, m.loHandler, m.lcDelegate+"_Setup",0)
= bindevent(m.toSource, m.tcEvent, m.loHandler, m.lcDelegate+"_TearDown",1)
return
function UnWrap(toSource)
*-- ok, here it gets really ugly
*-- in demo code trying to hint at better cleanup
local laEv[1], lnRun
for lnRun = 1 to aevents(laEv, m.toSource)
= unbindevents(m.toSource, laEv[m.lnRun, 3], laEv[m.lnRun, 2], laEv[m.lnRun, 4])
next
return
enddefine
define class Logger_Base as EvWrapper
*--- timing log does not need special info, dummy parameter,
*--- don't overdo, as vfp parameters are slooooow
function Log_Setup(dum1, dum2, dum3)
= this.Log_Do("Setup")
function Log_TearDown(dum1, dum2, dum3)
= this.Log_Do("TearDown")
function Log_Do(tcFrom)
local laEv[1]
= aevents(laEv, 0)
? str(seconds(), 12, 4) + " at " + m.tcFrom ;
+ ">>>" + laEv[1].Class + "::" + laEv[2]
return
enddefine
*****************************************************
* here is the huge customer app where I am tasked to identify the slow parts
* I don't want to mess *inside* their code too much, as subclass methods will also have code
* and not will depend on properties to be slow
define class Worker_Base as custom
nVal = 1
nSav = 1
nWrk = 1
function Simulate(tnVal)
wait window program(program(-1)-1) timeout m.tnVal
wait clea
return
function destroy()
*-- ahemmm... good habits done ugly...
= poLog.UnWrap(this)
return dodefault()
function Do_Job()
= this.Do_wrk()
= this.Do_Val(1)
= this.Do_Sav("", 0)
function Do_wrk()
= this.Simulate(this.nWrk)
function Do_Val(toObj)
= this.Simulate(this.nVal)
function Do_Sav(toObj, tcTable)
= this.Simulate(this.nSav)
enddefine
define class Worker_Fast as Worker_Base
nVal = 0.2
nSav = 0.1
nWrk = 0.4
enddefine
define class Worker_Slow as Worker_Base
nVal = 2
nSav = 2
nWrk = 3
enddefine
define class Worker_Sloppy as Worker_Slow
nVal = 0.2
nSav = 3
nWrk = 1
enddefine