Igor,
based on ILDasm RaiseItemCheck/add_itemCheck/remove_itemCheck (see the code
snippet in prev. reply), it takes Events[] from ComponentModel, so I don;t
believe they have internal array of delegates.
============================================================================
=================================
.method family hidebysig newslot virtual
instance void RaiseItemCheck(class
DevExpress.XtraEditors.Controls.ItemCheckEventArgs e) cil managed
{
// Code size 35 (0x23)
.maxstack 3
.locals init (class DevExpress.XtraEditors.Controls.ItemCheckEventHandler
V_0)
IL_0000: ldarg.0
IL_0001: call instance class [System]System.ComponentModel.EventHandlerList
[System]System.ComponentModel.Component::get_Events()
IL_0006: ldarg.0
IL_0007: ldfld object
DevExpress.XtraEditors.BaseCheckedListBoxControl::itemCheckID
IL_000c: callvirt instance class [mscorlib]System.Delegate
[System]System.ComponentModel.EventHandlerList::get_Item(object)
IL_0011: castclass DevExpress.XtraEditors.Controls.ItemCheckEventHandler
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: brfalse.s IL_0022
IL_001a: ldloc.0
IL_001b: ldarg.0
IL_001c: ldarg.1
IL_001d: callvirt instance void
DevExpress.XtraEditors.Controls.ItemCheckEventHandler::Invoke(object,
class DevExpress.XtraEditors.Controls.ItemCheckEventArgs)
IL_0022: ret
} // end of method BaseCheckedListBoxControl::RaiseItemCheck
.method public hidebysig specialname instance void
add_ItemCheck(class DevExpress.XtraEditors.Controls.ItemCheckEventHandler
'value') cil managed
{
// Code size 19 (0x13)
.maxstack 3
IL_0000: ldarg.0
IL_0001: call instance class [System]System.ComponentModel.EventHandlerList
[System]System.ComponentModel.Component::get_Events()
IL_0006: ldarg.0
IL_0007: ldfld object
DevExpress.XtraEditors.BaseCheckedListBoxControl::itemCheckID
IL_000c: ldarg.1
IL_000d: callvirt instance void
[System]System.ComponentModel.EventHandlerList::AddHandler(object,
class [mscorlib]System.Delegate)
IL_0012: ret
} // end of method BaseCheckedListBoxControl::add_ItemCheck
.method public hidebysig specialname instance void
remove_ItemCheck(class DevExpress.XtraEditors.Controls.ItemCheckEventHandler
'value') cil managed
{
// Code size 19 (0x13)
.maxstack 3
IL_0000: ldarg.0
IL_0001: call instance class [System]System.ComponentModel.EventHandlerList
[System]System.ComponentModel.Component::get_Events()
IL_0006: ldarg.0
IL_0007: ldfld object
DevExpress.XtraEditors.BaseCheckedListBoxControl::itemCheckID
IL_000c: ldarg.1
IL_000d: callvirt instance void
[System]System.ComponentModel.EventHandlerList::RemoveHandler(object,
class [mscorlib]System.Delegate)
IL_0012: ret
} // end of method BaseCheckedListBoxControl::remove_ItemCheck
============================================================================
=================================
-Serge
Igor Zinkovsky said:
Serge,
The 1st condition "((1) ItemCheck event is defined in a way that caused the
compiler to define a private delegate with the same name)" was making an
assumption that the BaseControl class did not use accessors in defining
ItemCheck event. The assumption was relying on the compiler declaring a
private delegate with "ItemCheck" name. Since BaseControl does use
accessors for ItemCheck event - we can no longer assume that there is going
to be a private delegate with "ItemCheck" name.
Do you know any implementation details about the class for which you have
"Events" member in BaseControl?
Looking at the code you provided below, I am assuming that the class has an
internal data structure (array ?) that contains a list of delegate chains,
which are obtained through an indexer (based on itemCheckID). Without
knowing more about that data structure you can't reflect on the specific
ItemCheckEventHandler reference (that points to the delegate chain) in order
to temporarily set it to null.
Thanks,
Igor Zinkovsky [MSFT]
Visual Studio Build/Release Team
This posting is provided "AS IS" with no warranties, and confers no rights.
Use of included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm
Serge Shimanovsky said:
Igor,
I know. But this does not work either. Both of them return NULL.
They have declaration smth. like this:
--------------------------------------------------------------------------
--
--------------------
public abstract class BaseControl : BaseGrandparentControl
{
...
private readonly object itemCheckID = new object();
public event ItemCheckEventHandler ItemCheck {
add { Events.AddHandler(itemCheckID, value); }
remove { Events.RemoveHandler(itemCheckID, value); }
}
public delegate void ItemCheckEventHandler(object sender,
ItemCheckEventArgs e);
....
protected virtual void RaiseItemCheck(ItemCheckEventArgs e) {
ItemCheckEventHandler handler =
(ItemCheckEventHandler)Events[itemCheckID];
if(handler != null) handler(this, e);
}
}
public class controlX : BaseControl {
}
So, the
FieldInfo f =
this.controlX.GetType().BaseType.GetField("ItemCheck",
BindingFlags.Instance| BindingFlags.NonPublic);
or
FieldInfo f =
this.controlX.GetType().BaseType.GetField("ItemCheck",
BindingFlags.Instance| BindingFlags.Public);
return NULL. Any ideas?
-Serge
--------------------------------------------------------------------------
--
---------------------------
message Serge,
If I understand correctly, "ItemCheck" event is declared in some base
class,
and the class of controlX derives from that base class?
If this is correct - try using the "BaseType" property of the controlX's
type to get the type of the base class:
FieldInfo f = this.controlX.GetType().BaseType.GetField("ItemCheck",
BindingFlags.Instance| BindingFlags.NonPublic);
Thanks,
Igor Zinkovsky [MSFT]
Visual Studio Build/Release Team
This posting is provided "AS IS" with no warranties, and confers no
rights.
Use of included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm
Igor,
This is Ok as well as they have declaration of this handler in this
class,
but they do have this in the base class, so GetField() and .SetValue()
would
not work. Isn't it?
-Serge
"Igor Zinkovsky [MSFT]" <
[email protected]>
wrote
in
message Serge, you can use the following, given that: (1) ItemCheck
event
is
defined
in a way that caused the compiler to define a private delegate with
the
same
name (2) Class where ItemCheck is declared allows modification of
private
members through reflection:
private void controlX_DataSourceChanged(object sender,
System.EventArgs
e)
{
FieldInfo f = this.controlX.GetType().GetField("ItemCheck",
BindingFlags.Instance| BindingFlags.NonPublic);
ItemCheckEventHandler tempCopy =
(ItemCheckEventHandler)f.GetValue(this.controlX);
f.SetValue(this.controlX, null);
try
{
....
}
finally
{
f.SetValue(this.controlX, tempCopy);
}
}
Thanks,
Igor Zinkovsky [MSFT]
Visual Studio Build/Release Team
This posting is provided "AS IS" with no warranties, and confers no
rights.
Use of included script samples are subject to the terms
specified
at
http://www.microsoft.com/info/cpyright.htm
Igor,
Thank you very much. But the problem is that I'm using the
DevExpress
components and don't have access to their implementation. I
see
how
it
supoose to work, but lets say the situation I have right now. Is
there
any
other solution could be applied (I know the only way is to use
reflection,
but how?)
-Serge
in
message In your class (where ItemCheck is declared) you'll need to declare
a
private
delegate (to store listeners that sign up for ItemCheck event);
provide
add/remove accessors for ItemCheck event; and add extra
methods
to
save/restore the event:
class ...
{
private ItemCheckEventHandler _ItemCheck;
private ItemCheckEventHandler _SavedItemCheck;
public event ItemCheckEventHandler ItemCheck
{
add
{
_ItemCheck += new ItemCheckEventHandler(value);
}
remove
{
_ItemCheck -= new ItemCheckEventHandler(value);
}
}
// The method that fires the event needs to be changed to
trigger
the
private _ItemCheck
protected virtual void OnItemCheck()
{
ItemCheckEventHandler tempCopy = _ItemCheck;
if(tempCopy != null)
tempCopy(this, Args);
}
public void ClearItemCheck()
{
_SavedItemCheck = _ItemCheck;
_ItemCheck = null;
}
public void RestoreItemCheck()
{
_ItemCheck = _SavedItemCheck;
}
}
Hope this helps.
Igor Zinkovsky [MSFT]
Visual Studio Build/Release Team
This posting is provided "AS IS" with no warranties, and confers
no
rights.
Use of included script samples are subject to the terms specified
at
http://www.microsoft.com/info/cpyright.htm
message
It would be nice, but doing this way I have the following error:
error CS0079: The
event
'DevExpress.XtraEditors.BaseCheckedListBoxControl.ItemCheck'
can only appear on the left hand side of += or -='
Any suggestions?
-Serge
"Igor Zinkovsky [MSFT]"
wrote
in
message Hi Serge.
If you want to temporarily clear ALL listeners that have
signed
up
for
your
ItemCheck event - you can use the way that you've provided
here
(1.
store
the delegate chain in a local variable, 2. set your ItemCheck
event
to
null, 3. do some work, 4. restore ItemCheck from your local
copy):
private void controlX_DataSourceChanged(object sender,
System.EventArgs
e)
{
ItemCheckEventHandler tempCopy = this.controlX.ItemCheck;
this.controlX.ItemCheck = null;
try
{
....
}
finally
{
this.controlX.ItemCheck = tempCopy;
}
}
In addition, you need to be careful if your app is
multithreaded.
This
is
to prevent situations when one thread has just removed all
event
listeners,
and another thread is trying to raise the event:
private void OnItemCheck()
{
ItemCheckEventHandler tempCopy = this.controlX.ItemCheck;
//
This
will create a new delegate chain since delegates are immutable
if(tempCopy != null)
tempCopy(this, Args);
}
Thanks,
Igor Zinkovsky [MSFT]
Visual Studio Build/Release Team
This posting is provided "AS IS" with no warranties, and
confers
no
rights.
Use of included script samples are subject to the terms
specified
at
http://www.microsoft.com/info/cpyright.htm
message
Hi,
I have a situation where I need to clear the event sinks
from
an
event.
But
let's say I don't know which methods (by name, I mean)
signed
up
for
that
event.
I do have a control with lets say two events:
ItemCheck
and
DataSourceChange. Callbacks assigned to ItemCheck and
DataSourceChange
events at designtime.
The logic within DataSourceChanged callback requires
temporary
to
disable
the ItemCheck which can be accomplished by smth. Like this:
private void controlX_DataSourceChanged(object sender,
System.EventArgs
e)
{
this.controlX.ItemCheck -= new
ItemCheckEventHandler(this.controlX_ItemCheck);
try
{
....
}
finally
{
this.controlX.ItemCheck += new
ItemCheckEventHandler(this.controlX_ItemCheck);
}
}
Now, the question is how to do the same thing without
explicitly
specifying
this.controlX_ItemCheck name? I'm looking for
something
like
I
was
able
to
do in Delphi, for example,
1) store the existing one to the local variable
2) assign this one to null
3) do some work here...
4) restore back to the one stored into local variable
I believe you know what I'm talking about.
I know I have to use reflection in .NET/C# in order to get
this
thing
done,
but how?
P.S. Such things does not help because I have to
specify
the
name
of
the
callback explicitly as well:
// EventInfo ei = (sender as
MyControl).GetType().GetEvent("ItemCheck");
// Delegate d =
Delegate.CreateDelegate(ei.EventHandlerType,
this,
"controlX_ItemCheck");
ei.RemoveEventHandler(sender, d);
try
{
...
}
finally
{
ei.AddEventHandler(sender, d);
}
Thanks in advance,
Serge