So, the documentation that I've found online so far regarding the Invoke property doesn't seem to be particularly good, which is actually kind of annoying, believe it or not. I understand what Invoke does - you can't safely access the GUI directly, so an invoke does it in a safe way. That's fine, but I don't understand the variables that go into the method. If I wanted to, for instance, remove text from a listbox, how would I do that? I get about this far before I get a bit lost.
private void DoStuff(string TextIWouldBeRemoving)
{
if (listboxname.InvokeRequired)
{
listboxname.Invoke(SomeMysteriousParamaters, new object[] { TextIWouldBeRemoving )};
}
}
The first parameter is the method you want to safely invoke, the second parameter is an object array of the arguments to that method
So you would write:
private void DoStuff(string TextIWouldBeRemoving)
{
if (listboxname.InvokeRequired)
{
listboxname.Invoke(DoStuff, new object[] { TextIWouldBeRemoving )};
}
else
{
// Actually remove the text here!
}
}
Invoke is all about threading.
You need to do an invoke whenever you have created a separate thread in your code, and you need to update the User Interface elements from withing the code, that is executing in that newly create thread.
You can use a BeginInvoke, instead of a synchronous Invoke method. This article has a good example:
http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx
private void button1_Click(object sender, EventArgs e)
{
if (listBox1.InvokeRequired)
{
Action<string> d = DoAnything;
listBox1.Invoke(d, new object[] { "Item 1" });
}
else
DoAnything("Item 1");
}
void DoAnything(string itemText)
{
listBox1.Items.Remove(itemText);
}
Related
I'm C# with Compact Framework and I realized something weird today. I'm calling a method by an event that applies a set to an object and when I debug, it passes by this, but just performs after the last close bracket of the method. My example:
public string Loading
{
set { lblLoading.Text = value; }
}
private void btnAuth_Click(object sender, EventArgs e)
{
Loading = "Loading...";
_presenter.PerformAuth();
}
When I debug, it passes by my first statement, applies it, but doesn't change anything on the screen... Oh, until it do PerformAuth(). After it, so, then the label value is changed. Oh, the problem isn't just by it be synchronous. The same occurs when I try to do an asynchronous task:
private void btnAuth_Click(object sender, EventArgs e)
{
ASyncResult res = BeginInvoke(new Action(() =>Loading = "Loading..."));
EndInvoke(res);
_presenter.PerformAuth();
}
I think it might be a bug in thread and in C# design implementation. And also with direct set it is stubborn to me. As you can see in the image below:
I just want to set a text in a label, call a method and unset it in an event. Why does C# get it so complicated?
I've got serial data coming in to my application and by definition, it's async, so I'm running into troubles when trying to update a label to show what the incoming data is. Every now and then, I get an error on the lblRx.AsyncUpdate line, telling me the object is in use elsewhere.
At present, I use the following code;
private void IODataReceived(object sender, IODataEventArgs e)
{
lblRx.AsyncUpdate(() => lblRx.Text = string.Format("{0}:\t{1}", e.Timestamp, e.Data));
SetBackColors(false, eIODirection.In);
}
public static void AsyncUpdate(this Control ctrl, ActionCallback action)
{
if (ctrl != null)
{
if (!ctrl.IsHandleCreated && ctrl.IsDisposed)
ctrl.CreateControl(); // MSDN says CreateControl() is preferred over CreateHandle().
if (!ctrl.IsDisposed)
AsyncInvoke(ctrl, action);
}
}
The AsyncUpdate method isn't an issue (AFAIK...works well in other situations).
I think I need to put a lock on the control before calling AsyncUpdate. Or is there a better way to handle this situation?
i´m a beginner in C#,
a start a new Thread
pollprintthread = new System.Threading.Thread(PollPrint);
pollprintthread.Start();
in this Thread i call a function with a Datagridview
void PollPrint()
{
(some code)
printausfueren();
(some code)
}
public void printausfueren()
{
(some Code)
object[] row = { sqlReader[0], sqlReader[1], sqlReader[3], sqlReader[2], sqlReader[4], sqlReader[5], sqlReader[6], sqlReader[7] };
dataGridViewPrint.Rows.Add(row);
(some Code)
}
but i can´t use printausfuheren().invoke, i found any tutorials but only for Static Methods
Please Help :)
You can find a good explanation here: https://stackoverflow.com/a/12179408/67038
However, I would recommend that you wrap your call to dataGridViewPrint.Rows.Add in a method and call that method instead.
You will want to do this because there may be other actions that you wish to take on the UI when you add those rows.
For example, if you are adding a lot of rows, you are going to want to call BeginEdit/EndEdit on the grid, so that it does not try to repaint itself for every row that you add:
public void printausfueren()
{
//(some Code)
object[] rows = { sqlReader[0], sqlReader[1], sqlReader[3], sqlReader[2], sqlReader[4], sqlReader[5], sqlReader[6], sqlReader[7] };
dataGridViewPrint.Invoke(new Action(() => LoadGrid(rows)));
//(some Code)
}
private void LoadGrid(object[] rows)
{
// only need BeginEdit/EndEdit if you are adding many rows at a time
dataGridViewPrint.BeginEdit(false);
dataGridViewPrint.Rows.Add(rows);
dataGridViewPrint.EndEdit();
}
You can easily use anonymous methods to do complex invokes, such as:
yourForm.Invoke( (MethodInvoker) delegate() { dataGridViewPrint.Rows.Add(row); } );
This will auto-magically capture the row instance etc.
Every time I update the view of my program from a thread other than the element was created from, I use:
if (this.table.InvokeRequired)
{
this.table.Invoke(new MethodInvoker(delegate
{
this.table.Controls.Add(newRow);
this.table.Controls.SetChildIndex(newRow, this.table.Controls.Count);
}));
}
else
{
this.table.Controls.Add(newRow);
this.table.Controls.SetChildIndex(newRow, this.table.Controls.Count);
}
Even though this approach works fine, I doubt that it's the best-practice to do it that way since
this.table.Controls.Add(newRow);
this.table.Controls.SetChildIndex(newRow, this.table.Controls.Count);
is basically the same for invoking and not invoking.
Any ideas how I could improve that?
You can put it in a method, then the method can invoke itself:
public void addRow(Control newRow) {
if (this.table.InvokeRequired) {
this.table.Invoke(new MethodInvoker(addRow), new object[]{ newRow });
} else {
this.table.Controls.Add(newRow);
this.table.Controls.SetChildIndex(newRow, this.table.Controls.Count);
}
}
The syntax might not be exactly right, but roughly:
delegate void myedelegate(<mystuff>)
void UpdateSomething(<mystuff>)
if(this.invokerequired)
{
mydelegate updater = new mydeleate(UpdateSomething);
updater.invoke(new object[]{<mystuff>})
}
else
{
//doupdate
}
Also, see http://www.codeproject.com/Articles/37642/Avoiding-InvokeRequired for a good guide on invoke required practices
Lets say i have an asynchoronous call in my monotouch project like this
context.getNameCompleted += HandleContextgetNameCompleted;
context.getNameAsync();
void HandleContextgetNameCompleted(object sender, getNameCompletedEventArgs args)
{
string name = args.Result;
}
Now how do I get another asynchronous method running that relies on the completion of the first without getting the program to crash. So for instance my second call might be
context.getAgeCompleted += HandleContextgetAgeCompleted;
context.getAgeAsync();
void HandlegetAgeCompleted(object sender, getAgeCompletedEventArgs args)
{
string age = args.Result;
}
the second method can only return a value once we return the "name" from the first person. Please provide in reasons and/or examples of how to properly use this method or any alternate solution.As usual your help is much appreciated
Fire the 2nd request when you handle the completion of the first one.
void HandleContextgetNameCompleted(object sender, getNameCompletedEventArgs args)
{
string name = args.Result;
context.getAgeCompleted += HandleContextgetAgeCompleted;
context.getAgeAsync();
}