Link to home
Start Free TrialLog in
Avatar of margarit
margaritFlag for Israel

asked on

C# - Invoke problem

Hello,

I have the following problem.
I get an attached exception on:
 this.Invoke(even, new object[] { buffer }); (line 17)

What do I do wrong?

Please help
Margarit

delegate void SetSlave(byte[] buffer);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            System.Threading.Thread.Sleep(500);
            byte[] buff = new byte[249];
            port.Read(buff, 0, 249); 
            SetSlavesData(buff); 
}
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void SetSlavesData(byte[] buffer)
        {
            if (this.InvokeRequired)
            {
                SetSlave even = new SetSlave(SetSlavesData);
                this.Invoke(even, new object[] { buffer });
            }
            else
            {
                int numOfSlaves, sentStrings;

Open in new window

1.JPG
Avatar of abel
abel
Flag of Netherlands image

The error says that you use the wrong arguments. What is the declaration of the method you are invoking? It looks like you are only sending one argument, the buffer, and the error actually says that you need at least another argument: count.

Btw, you say "Invoke" but this is not a typical Invoke/Reflection question, correct? Can you show the body of Invoke?
Avatar of margarit

ASKER

Hello,
Thanks for the fast reply.
The declaration of method is: private void SetSlavesData(byte[] buffer)

Buffer is an array. Maybe here is a problem?
THANKS

private void SetSlavesData(byte[] buffer)
        {
            if (this.InvokeRequired)
            {
                SetSlave even = new SetSlave(SetSlavesData);
                this.Invoke(even, new object[] { buffer });
            }
            else
            {
                int numOfSlaves, sentStrings;
 
                numOfSlaves = buffer[1];     
                sentStrings = buffer[2];     
 
                this.slavesTable.Rows.Clear();
                this.slavesTable.Rows.Add(numOfSlaves);
          }
        }

Open in new window

Do I understand this right, you are calling invoke using a delegate to call yourself recursively?

When you hover over the buffer, is it filled? I don't know why, but the error seems to come from somewhere else.

Normally, you do not need to do "new object[] { buffer}", not even with Invoke. I tried it to be sure, but when you use a byte array, it is fine if remove the array constructor:

this.Invoke(even, buffer);
but i'm afraid that all this is not really of any help to resolve your error.

Just as an example, i dug up a button_click event with a basic version of your code. It runs without errors:

delegate void TestArrayDelegate(byte[] b_array);
private void Q24344645_Click(object sender, EventArgs e)
{
    byte[] myArray = new byte[] {0,1,2};
    TestArrayDelegate myFunc= new TestArrayDelegate(DoTestArray);
    this.Invoke(myFunc, new object[] {myArray});
    // or: this.Invoke(myFunc, myArray);
}
 
private void DoTestArray(byte[] buffer)
{
    Debug.WriteLine(buffer[0]);
}

Open in new window

Avatar of Cebik
hi :)
check this

public delegate void SetSlavesDataDelegate(byte[] buffer);
private void SetSlavesData(byte[] buffer)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new SetSlavesDataDelegate(SetSlavesData), buffer);
    }
    else
    {
        int numOfSlaves, sentStrings;
 
        numOfSlaves = buffer[1];     
        sentStrings = buffer[2];     
 
        this.slavesTable.Rows.Clear();
        this.slavesTable.Rows.Add(numOfSlaves);
  }
}

Open in new window

i sow now that you probably have delgate with other name so:
this will work..

public delegate void SetSlave(byte[] buffer);
private void SetSlavesData(byte[] buffer)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new SetSlave(SetSlavesData), buffer);
    }
    else
    {
        int numOfSlaves, sentStrings;
 
        numOfSlaves = buffer[1];     
        sentStrings = buffer[2];     
 
        this.slavesTable.Rows.Clear();
        this.slavesTable.Rows.Add(numOfSlaves);
  }
}

Open in new window

@Cebik, what's the difference between my approach and your approach, or were you just following up on that? Btw, using "new object[]" or not doesn't break the code, strange as it may seem.
so what's wrong with her code?
i writed the same code like her...
but in my code i'm not using "new object[]" and it's working! (checked!)
that's why i writed it..
ok.. i've found the same using in your code now..
so the differents is that i corrected her code not making new correct code

i didn't want to take your points :)
and.. she is doing this because she is changing properties on a form from different thread..
maybe the problem is that you are getting element index 1 and 2 not 0 and 1..
here is example app based on your..
make new windows application and paste the code..

good luck margarit! :)

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        DataGridView slavesTable = new DataGridView();
 
        public Form1()
        {
            InitializeComponent();
 
            slavesTable.Dock = DockStyle.Fill;
            slavesTable.Columns.Add("0", "0");
            slavesTable.Columns.Add("1", "1");
            slavesTable.Columns.Add("2", "2");
            this.Controls.Add(slavesTable);
        }
 
        public delegate void SetSlave(byte[] buffer);
        private void SetSlavesData(byte[] buffer)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new SetSlave(SetSlavesData), buffer);
            }
            else
            {
                int numOfSlaves, sentStrings;
 
                //numOfSlaves = buffer[0];  //indexing starting from 0 to elements count -1 !!
                numOfSlaves = buffer[1];
                sentStrings = buffer[2];
 
                //this.slavesTable.Rows.Clear();
                //this.slavesTable.Rows.Add(numOfSlaves);
                this.slavesTable.Rows.Add(buffer[0], buffer[1], buffer[2]);
            }
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            Thread nt = new Thread(new ThreadStart(Thread1));
            nt.Start();
        }
 
        private void Thread1()
        {
            Random rnd = new Random();
            while(true)
            {
                Thread.Sleep(1000);
                byte[] buffer = new byte[] { Convert.ToByte(rnd.Next(0, 255)), Convert.ToByte(rnd.Next(0, 255)), Convert.ToByte(rnd.Next(0, 255)) };
                SetSlavesData(buffer);
            }
        }
    }
}

Open in new window

No problem, it just looked a bit strange. Sorry for fuzzing about it...

Btw, as you noticed, this is apparently about cross-thread calls. I am wondering about the error, though. It mentions a parameter "count" which isn't there and is apparently wrong. I don't see that parameter on the place of the error. Is the error really occurring on that point, or at a deeper level, which is somehow hidden for the debugger?
that's right..
it must be somwhere else..
she must give us stack trace..
i've checked this.. and both of this is working..


this.Invoke(myFunc, new object[] {myArray});
this.Invoke(myFunc, myArray);

Open in new window

(if you don't want to know the whole story behind it, or how to keep this from happening in the future, just read the bold lines below)
The error
I think, Cebik, that you are on the right page there. The buffer is, of course, indexed from zero. But the error received is not about IndexOutOfRangeException (see screenshot 1), but about an ArgumentOutOfRangeException. I was puzzled by that, because there seemed to be no call where that actually happened.

The count param
Until my eye was caught by the Rows.Add(count) method. That was where the "count" parameter was! Assuming that slavesTable was a DataGridView I tried to mimic the situation again and this time I succeeded.

Not the right line
My last comment, about the error taking place somewhere else, was apparently correct. See the second screenshot. The Visual Studio Debugger is not capable of diving into the queued method (see http://weblogs.asp.net/justin_rogers/pages/126345.aspx for what happens under the hood) and shows the line where the Invoke takes place.

How to debug
So, how could you actually debug this correctly? Quite simply: put a breakpoint at the beginning of the method (just after the "else") that is being invoked and you can step through it with F10.

How to solve
How to solve it? Possibly by following up on Cebik's advice: maybe you have the wrong index. Or maybe you didn't want to use the data in the buffer at all as count for adding rows (as Cebik suggests) and you just want to add the contents of the buffer.

The code that Cebik shows you will add three cells in one new row.

The code that you had originally, will add buffer[1] amount of rows. Because buffer[1] was holding zero or a negative value, you got the error you saw.

Now you know what is actually going on, you know how to solve it, to debug it and how to display it.

-- Abel --

ScreenShot232.png
ScreenShot231.png
ASKER CERTIFIED SOLUTION
Avatar of abel
abel
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
i was thinking about this rows.add also but i was almoust sleep yesterday..
glories for you ;)
THANKS A LOT