need to make an asynchronous call to a method that accepts arguments and then modifies form
-
hi all. i need to make a call to a method asynchronously. this method accepts arguments. the method also returns a value that is then used to modify a form obviously created by the main thread. to keep things simple, i created a prototype of what i'm trying to do. here's the code:
public partial class Form1 : Form
{
public delegate int SomeMethod();public Form1() { InitializeComponent(); } private void button1\_Click(object sender, EventArgs e) { //AddToList(IntFetcher.SlowFetch()); SomeMethod method = IntFetcher.SlowFetch; method.BeginInvoke(EndFetchInt, method); } public void EndFetchInt(IAsyncResult result) { SomeMethod method = result.AsyncState as SomeMethod; int i = method.EndInvoke(result); MethodInvoker mi = new MethodInvoker(this.AddToList); this.BeginInvoke(mi, i); } public void AddToList() { int i = 0; ListViewItem lvi = new ListViewItem(); lvi.Text = i.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } public void AddToList(int data) { ListViewItem lvi = new ListViewItem(); lvi.Text = data.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } } public static class IntFetcher { public static int SlowFetch() { // Simulate a slow i/o process Thread.Sleep(3150); Random random = new Random(DateTime.Now.Millisecond); return random.Next(100, 500); } }
I had to create the
AddToList()
method to be confirm if the code was being called at all and to determine if it could modify the listview control. It did. But i still couldnt figure out a way to pass the value returned from the function to it. I usedMethodInvoker
cos without it, I got an exception telling me that the running thread could not modify the control as it was created by the main thread. Any contributions will be appreciated. Thanks. -
hi all. i need to make a call to a method asynchronously. this method accepts arguments. the method also returns a value that is then used to modify a form obviously created by the main thread. to keep things simple, i created a prototype of what i'm trying to do. here's the code:
public partial class Form1 : Form
{
public delegate int SomeMethod();public Form1() { InitializeComponent(); } private void button1\_Click(object sender, EventArgs e) { //AddToList(IntFetcher.SlowFetch()); SomeMethod method = IntFetcher.SlowFetch; method.BeginInvoke(EndFetchInt, method); } public void EndFetchInt(IAsyncResult result) { SomeMethod method = result.AsyncState as SomeMethod; int i = method.EndInvoke(result); MethodInvoker mi = new MethodInvoker(this.AddToList); this.BeginInvoke(mi, i); } public void AddToList() { int i = 0; ListViewItem lvi = new ListViewItem(); lvi.Text = i.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } public void AddToList(int data) { ListViewItem lvi = new ListViewItem(); lvi.Text = data.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } } public static class IntFetcher { public static int SlowFetch() { // Simulate a slow i/o process Thread.Sleep(3150); Random random = new Random(DateTime.Now.Millisecond); return random.Next(100, 500); } }
I had to create the
AddToList()
method to be confirm if the code was being called at all and to determine if it could modify the listview control. It did. But i still couldnt figure out a way to pass the value returned from the function to it. I usedMethodInvoker
cos without it, I got an exception telling me that the running thread could not modify the control as it was created by the main thread. Any contributions will be appreciated. Thanks.Hi, Have a look at the link. Hope this helps. http://en.csharp-online.net/CSharp_Delegates_and_Events%E2%80%94Asynchronous_method_calls[^]
-
Hi, Have a look at the link. Hope this helps. http://en.csharp-online.net/CSharp_Delegates_and_Events%E2%80%94Asynchronous_method_calls[^]
i still got this exception Cross-thread operation not valid: Control 'listView1' accessed from a thread other than the thread it was created on. while calling the AddToList() method directly from the callback method using the procedure outlined on that url. combed thru msdn and got this url http://msdn.microsoft.com/en-us/library/ms171728.aspx which is supposed to help make thread-safe calls to windows form controls. trying to understand the methods outlined there.
-
hi all. i need to make a call to a method asynchronously. this method accepts arguments. the method also returns a value that is then used to modify a form obviously created by the main thread. to keep things simple, i created a prototype of what i'm trying to do. here's the code:
public partial class Form1 : Form
{
public delegate int SomeMethod();public Form1() { InitializeComponent(); } private void button1\_Click(object sender, EventArgs e) { //AddToList(IntFetcher.SlowFetch()); SomeMethod method = IntFetcher.SlowFetch; method.BeginInvoke(EndFetchInt, method); } public void EndFetchInt(IAsyncResult result) { SomeMethod method = result.AsyncState as SomeMethod; int i = method.EndInvoke(result); MethodInvoker mi = new MethodInvoker(this.AddToList); this.BeginInvoke(mi, i); } public void AddToList() { int i = 0; ListViewItem lvi = new ListViewItem(); lvi.Text = i.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } public void AddToList(int data) { ListViewItem lvi = new ListViewItem(); lvi.Text = data.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } } public static class IntFetcher { public static int SlowFetch() { // Simulate a slow i/o process Thread.Sleep(3150); Random random = new Random(DateTime.Now.Millisecond); return random.Next(100, 500); } }
I had to create the
AddToList()
method to be confirm if the code was being called at all and to determine if it could modify the listview control. It did. But i still couldnt figure out a way to pass the value returned from the function to it. I usedMethodInvoker
cos without it, I got an exception telling me that the running thread could not modify the control as it was created by the main thread. Any contributions will be appreciated. Thanks.First, based on documentation for
MethodInvoker
: This API supports the .NET Framework infrastructure and is not intended to be used directly from your code Second, presumably the MethodInvoker executes the method passed in another thread so it basically the problem is exactly what the error says. Take a look at BackgroundWorker Class[^]. I believe it would be helpful in your case.The need to optimize rises from a bad design
-
First, based on documentation for
MethodInvoker
: This API supports the .NET Framework infrastructure and is not intended to be used directly from your code Second, presumably the MethodInvoker executes the method passed in another thread so it basically the problem is exactly what the error says. Take a look at BackgroundWorker Class[^]. I believe it would be helpful in your case.The need to optimize rises from a bad design
Thanks Mika, but i got it working already. the problem i had was marshalling the background thread to the main one. this was the modification i made to get it to work.
public void EndFetchInt(IAsyncResult result) { SomeMethod method = (SomeMethod)result.AsyncState; int i = method.EndInvoke(result); //MethodInvoker mi = new MethodInvoker(this.AddToList); //this.BeginInvoke(mi, i); AddToList(i); } delegate void \_addToList(int data); public void AddToList(int data) { if (this.listView1.InvokeRequired) { this.Invoke(new \_addToList(AddToList), data); } else { ListViewItem lvi = new ListViewItem(); lvi.Text = data.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } }
i would have had to do the same if even if i had used the BackgroundWorker class.
-
Thanks Mika, but i got it working already. the problem i had was marshalling the background thread to the main one. this was the modification i made to get it to work.
public void EndFetchInt(IAsyncResult result) { SomeMethod method = (SomeMethod)result.AsyncState; int i = method.EndInvoke(result); //MethodInvoker mi = new MethodInvoker(this.AddToList); //this.BeginInvoke(mi, i); AddToList(i); } delegate void \_addToList(int data); public void AddToList(int data) { if (this.listView1.InvokeRequired) { this.Invoke(new \_addToList(AddToList), data); } else { ListViewItem lvi = new ListViewItem(); lvi.Text = data.ToString(); lvi.SubItems.Add(DateTime.Now.ToString()); listView1.Items.Add(lvi); } }
i would have had to do the same if even if i had used the BackgroundWorker class.
Glad you got it solved! Yeah, you have had to do the same in every implementation, but there was these two reasons why I suggested BackgroundWorker: - if I understood correctly, MethodInvoker shouldn't be used. If it's internal, it's not well documented and there are no quarantees for backward compatibility in future versions - with BW the model is easier to implement and therefore also more understandable But then again, are those valid reasons at all fully depend on your needs. Happy coding :)
The need to optimize rises from a bad design