I had send an email to you.robert wrote:xinjie,
Maybe you can send me a private email to we can discuss this ?
Robert
BindEvent() And other
BindEvent() And other
简单的东西重复做,你能成为专家;重复的东西用心做,你能成为赢家!
-
- Posts: 200
- Joined: Wed Oct 09, 2019 6:51 pm
BindEvent() And other
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.
I realize this is an old thread, but in vfp (due to the fact vfp always call the same method with different parameters filled or given) there is for me a huge benefit in BindEvent():
I can retrofit existing code with a homegrown profiler with minimal effort/source changes, if I need to I can "wrap" method calls even externally after objects have been loaded by reading a table with specific object instance names, object classes or decendants of object classes.
For this the vfp Bindevent NOT having to conform to the method signature of the wrapped method is ideal.
Perhaps the same effect might be realized in x# code depending on reflection, but even then result will be marred (in part) by same named methods calling each other with different (perhaps default) parameters.
So yes, I realize vfp BindEvent does not map to Dotnet delegates well - but the ability to wrap any named method either from object.init() or even very late by recursive dynamic calls walking the object tree with amembers() helping is a very powerful (and hackish) approach.
regards
thomas
BindEvent() And other
Thomas,
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 ?
Robert
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 ?
Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
The Netherlands
robert@xsharp.eu
-
- Posts: 200
- Joined: Wed Oct 09, 2019 6:51 pm
BindEvent() And other
Hi Robert,
This approach might be used on the cursoradapter class of the largest tables, as larger tables are more suspect of causing delays. The second approach - hooking in Init of base class (perhaps with property switch) would be used to log_time all cursoradapter.method calls suspect of causing delays for all tables, for instance across different machines or on different customer data sets.
Compared to coverage profiler this will give more realistic times, but I have specific C-logger .Fll functionality to check in more detail / with even less overhead / Heisenbug changes introduced by measuring, as well as specific "tableaction-wrappers" allowing me to see problematic/slow code parts.
Code tries to reduce to the max, but it DOES have cleanup (not needed in most situations), but the objects wrapped normally are have their own lists of what and where to clear - unwrap is more a hint than sober implementation and logging would be piped either into txt or dbf....
Fire up vfp, run and grin
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 ?
This approach might be used on the cursoradapter class of the largest tables, as larger tables are more suspect of causing delays. The second approach - hooking in Init of base class (perhaps with property switch) would be used to log_time all cursoradapter.method calls suspect of causing delays for all tables, for instance across different machines or on different customer data sets.
Compared to coverage profiler this will give more realistic times, but I have specific C-logger .Fll functionality to check in more detail / with even less overhead / Heisenbug changes introduced by measuring, as well as specific "tableaction-wrappers" allowing me to see problematic/slow code parts.
Code tries to reduce to the max, but it DOES have cleanup (not needed in most situations), but the objects wrapped normally are have their own lists of what and where to clear - unwrap is more a hint than sober implementation and logging would be piped either into txt or dbf....
Fire up vfp, run and grin
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