views:

531

answers:

2

Hello

I am receving an ArgumentException from the following code, I am struggling to understand it the last entry in the stack trace is

System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr,
                Binder binder, Object[] parameters, CultureInfo culture, 
                Boolean verifyAccess, StackCrawlMark& stackMark)

When I step through the DeviceResponse is populated as I expect and the target is located and as expected but the targetForm.Invoke throws everytime

Any help would be much appreciated.

The event is defined as:

public static event EventHandler<MsgEventArgs<DeviceResponse>> DeviceResponseReceived;

The event is being raised from this code:

//Raise the event
if (DeviceResponseReceived != null)
{
    if (DeviceResponseReceived.Target is System.Windows.Forms.Form)
    {
         System.Windows.Forms.Form targetForm = DeviceResponseReceived.Target as System.Windows.Forms.Form;
         targetForm.Invoke(DeviceResponseReceived, new MsgEventArgs<DeviceResponse>(deviceResponse));
    }
}

The MsgEventArgs is a generic event arguments class deriving from EventArgs:

public class MsgEventArgs<T> : EventArgs
{
    public MsgEventArgs(T value)
    {
        m_value = value;
    }
    private T m_value;
    public T Value
    {
        get { return m_value; }
    }
}

In my form I have registered for the event in the forms constructor:

DeviceResponse.DeviceResponseReceived += new EventHandler<MIASmartClient.Messaging.Transport.MsgEventArgs<DeviceResponse>>(DeviceResponse_DeviceResponseReceived);

With the implementation as:

void DeviceResponse_DeviceResponseReceived(object sender, MIASmartClient.Messaging.Transport.MsgEventArgs<DeviceResponse> e)
{
    _presenter.DeviceResponseReceived(e.Value);
}

Thanks for taking the time to have a look

A: 

Without having tried the code out, one thing strikes me as odd in the following code:

if (DeviceResponseReceived != null)
{
    if (DeviceResponseReceived.Target is System.Windows.Forms.Form)
    {
         System.Windows.Forms.Form targetForm = DeviceResponseReceived.Target as System.Windows.Forms.Form;
         targetForm.Invoke(DeviceResponseReceived, new MsgEventArgs<DeviceResponse>(deviceResponse));
    }
}

You check if the DeviceResponseReceived delegate (I assume it is?) is assigned, and then you tell targetForm to invoke that delegate. Where is the delegate actually pointing to? I would guess that what you really want to do is to invoke the corresponding method in targetForm?

Fredrik Mörk
Hello FredrikApologies for my lack of knowledge, I might be mis-understanding you but I have defined DeviceResponseReceivied as an event in the same class:public static event EventHandler<MsgEventArgs<DeviceResponse>> DeviceResponseReceivedI was expecting invoke to raise the event to the subscribed form on the correct UI Thread.Have I missed something fundamental?
SimonNet
+1  A: 

From the Msdn article on events:

Events are a special kind of multicast delegate that can only be invoked from within the class or struct where they are declared (the publisher class).

This makes sense. The class that declares the event (publisher) should be the only one who determines when and where the event is raised. This is also why event exposes only certain operations to client code (subscriber) such as subscribe and unsubcribe.

In your code, you're passing DeviceResponseReceived event as a delegate argument in targetForm.Invoke and expecting it to be invoked by the target (Form). Target is not where the event is declared hence the exception.

You want to ensure that DeviceResponse_DeviceResponseReceived event handler is executed on the UI thread since it is propably touching the UI components. Then in there you can check if InvokeRequired. Check out WinForms UI Thread Invokes for more information on how to update UI from other threads.

Mehmet Aras