I'm trying to modify a combo box on my WinForms application, and I'm getting some strange behavior. I'm trying two methods:
Here is the method I need to invoke:
private void modifyCombo(ClassInfoHolder oldClass, ClassInfoHolder newClass) {
this.monitoredComboBox.Items[monitoredComboBox.Items.IndexOf(oldClass)] = newClass;
}
I'm trying two different ways to invoke this method from the GUI thread. This one works:
delegate void modifyComboCollection(ClassInfoHolder oldClass, ClassInfoHolder newClass);
private void modifySecondTabComboBox(ClassInfoHolder oldClass, ClassInfoHolder newClass) {
if (monitoredComboBox.InvokeRequired) {
modifyComboCollection m = new modifyComboCollection(modifyCombo);
this.BeginInvoke(m, oldClass, newClass);
} else {
// no need for Invoke
modifyCombo(oldClass, newClass);
}
}
And this throws a TargetInvocationException:
this.BeginInvoke(new Action(() => {
modifyCombo(oldClass, newClass);
}));
I'd prefer to use the second because it's much clearer, but I'm not entirely sure why it throws an error when the first example works just fine. The first example calls the modifyCombo method and correctly returns the IndexOf of the object. The second example is returned -1 from IndexOf.
Edit: Here is a pastebin link of the stacktrace.
http://pastebin.com/TwfUDw4u
this.BeginInvoke(m, new[] {oldClass, newClass});
BTW. Good practice is to test if (this.IsHandleCreated && !this.IsDisposed) before use Invoke.
Related
I'm trying to wrap my head around different concepts in Csharp by trying different things. A create a generic function that takes in an action. The action has one input parameter and returns void. I create a simple action that is linked to a lambda function (returns void has one parameter x). I am able to run the action but when I pass the function to my generic function I am not sure how to add the input parameter. act("Some Int") doesn't work.
How do I pass in a value to an action?
public MainWindow()
{
InitializeComponent();
Action<int> myAction = (x) => Console.WriteLine(x);
myAction(13);
test(myAction);
}
private static void test<T>(Action<T> act)
{
act(); // How do i pass in an int Here?
}
Simply calling act("Some Int") as you have just required the Action act to be a genric function. Therefore you cannot specifically invoke it with one fixed variable type. You can solve your problem by modifying the test-method
private static void test<T>(Action<T> act, T value)
{
act(value); // How do i pass in an int Here?
}
...
test(myAction,integerValue);
Now you can call the Action with a given intvalue.
I can see what you are trying to do, and just wanted to throw this pattern up, since we often do this when we have to use closures and the parameters could be wildly different.
In those cases, rather than define an Action<T> which kind of ties you down from being able to use closures, you would just simply define your method as Action. So test would look like this:
private static void test(Action act)
{
act(); // yup, that's all there is to it!
}
So how would you pass in the parameter(s)? Simple: use closures. Like this:
public MainWindow()
{
InitializeComponent();
var x = 13; // this defined outside now...
Action myAction = () => Console.WriteLine(x); // you're basically using the closure here.
myAction();
test(myAction);
}
We often use this sort of approach when we're context switching (aka thread jumping), and need the thread continuation to pick up one or more variable values at the point it executes. That's just one example, there's quite a few other valid use cases as well.
Your experimental example, if I'm reading it correctly, could also qualify as a situation where closures could be a good fit.
In my application, I have a background thread that performs calculations and pushes the resultant ILnumerics arrays to the view.
I am having issues with ILNumerics arrays getting disposed off when I trigger the view update function with Control.BeginInvoke.
Are there any specific function rules to follow when passsing ILArrays as input arguments to BeginInvoke delegate?
Here is my sample code.
void IMainView.UpdateSpectrumData(ILInArray<float> wfmData)
{
if (InvokeRequired)
{
BeginInvoke(new MethodInvoker(() => AddWfmToView(wfmData)), new object[] { wfmData });
}
else
{
AddWfmToView(wfmData);
}
}
}
void AddWfmToView(ILInArray<float> wfmData)
{
using(ILScope.Enter(wfmData))
{
// update panel
}
}
The problem is that the compiler will create an anonymous class for you behind the scenes. It is needed to capture the variables used in the lambda expression. And for that class the compiler will not follow the ILNumerics function rules. This is why you see premature disposals.
The answer to your question is: ILArray is not supported in lambda expressions. Use it only with care and if you are aware of all subtleties related to it.
In your case, your can work around the problem by falling back to ILNumerics.ILArray class usage. Declare an attribute in your container class (form/control?) which holds the data to be used for updating. From your updating routine you can access the attribute normally. For most common scenarios you will not need any synchronization. (But as always: think about it and make a conscious decision!)
// a local attribute will 'transport' the data
ILArray<float> m_data = ILMath.localMember<float>();
public void UpdateView(ILInArray<float> wfmData) {
using (ILScope.Enter(wfmData)) {
m_data.a = wfmData;
AddWfmToView();
}
}
// the actual update method will not expose ILArray parameters. Hence we can use it in a lambda expression.
void AddWfmToView() {
if (InvokeRequired) {
Invoke(new MethodInvoker(() => AddWfmToView()));
} else {
// access control here if necessary
panel.Scene.First<ILLinePlot>().Update(m_data);
panel.Configure();
panel.Refresh();
}
}
I am writing GUI applications for some time now and one thing I always use are MethodInvoker + lambda functions to do cross-thread access.
From the examples I find I always see stuff like this:
Version 1
if (InvokeRequired)
{
Invoke(new MethodInvoker(() =>
{
Label1.Text = "Foobar";
});
}
else
{
Label1.Text = "Foobar";
}
However this leads to code-duplication --> major baddie to me.
So what's wrong with this?
Version 2
MethodInvoker updateText = new MethodInvoker(() =>
{
Label1.Text = "Foobar";
});
if (InvokeRequired)
{
Invoke(updateText);
}
else
{
updateText();
}
Now I have the functionality bundled in one variable and call it with Invoke or as a function pointer when appropriate. Is version 2 worse performance-wise? Or is i bad practice to use anonymous functions for this?
Nothing's wrong with it... but you can add an extension method to make it all somewhat nicer:
public static void InvokeIfNecessary(this Control control,
MethodInvoker action)
{
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
}
Then you can write:
this.InvokeIfNecessary(() => Label1.Text = "Foobar");
Much neater :)
There is a very slight performance drawback from creating a delegate when you don't need to, but it's almost certainly insignificant - concentrate on writing clean code.
Note that even if you don't want to do that, you can still make your variable declaration simpler in your existing code:
MethodInvoker updateText = () => Label1.Text = "Foobar";
That's one benefit of using a separate variable - you don't need the new MethodInvoker bit to tell the lambda expression what type of delegate you want...
Is version 2 worse performance-wise? Or is i bad practice to use anonymous functions for this?
No version 2 is better, don't worry about performance problems with it. Instead of using an anonymous function you could also define a method:
public void SetLabelTextToFooBar()
{
Label1.Text = "Foobar";
}
and then:
if (InvokeRequired)
{
Invoke(SetLabelTextToFooBar);
}
else
{
SetLabelTextToFooBar();
}
or simply use a BackgroundWorker which will automatically execute all callbacks (such as RunWorkerCompleted and ProgressChanged) on the main UI thread so that you don't need to check for InvokeRequired.
Another practice on doing it:
Invoke((MethodInvoker)delegate
{
Label1.Text = "Foobar";
});
After following this question on updating a GUI from another thread I wanted to extend the code slightly so that it worked for something other than property assignment. Specifically I was trying to find a way to assign some functionality directly to a lambda so that I can define the behavior as needed (I modified the original slightly for WPF):
private delegate void UpdateControlThreadSafeDelegate(Control control, System.Linq.Expressions.Expression<Action> property);
public void UpdateControl(Control control, System.Linq.Expressions.Expression<Action> property)
{
// If calling thread is not associated with control dispatcher, call our thread safe property update delegate
if (!control.Dispatcher.CheckAccess())
{
control.Dispatcher.Invoke(new UpdateControlThreadSafeDelegate(UpdateControl), new object[] { control, property });
}
else
{
Action call = property.Compile();
call();
}
}
With usage:
UpdateControl(lbFoo, () => lbFoo.Items.Clear()); // where lbFoo is a ListBox control
This works fine. But I'd rather allow do something like:
UpdateControl(lbFoo, () => { lbFoo.Items.Clear(); lbFoo.Items.Add("Bar");});
This does not work, returning error CS0834: A lambda expression with a statement body cannot be converted to an expression tree. The error is clear, I'm just not certain on how best to proceed. I could follow my original usage and do what I need in several lines, it's just not as tidy.
I'm guessing there is a better/easier way to do what I want.
If you don't use expressions, and just pass the action, like so:
public void UpdateControl(Control control, Action actionToExecute)
Then you can use this as written. The only other change will be your else statement, where you would just call this directly:
else
{
actionToExecute();
}
Which is more correct and why?
Control.BeginInvoke(new Action(DoSomething), null);
private void DoSomething()
{
MessageBox.Show("What a great post");
}
or
Control.BeginInvoke((MethodInvoker) delegate {
MessageBox.Show("What a great post");
});
I kinda feel like I am doing the same thing, so when is the right time to use MethodInvoker vs Action, or even writing a lambda expression?
EDIT: I know that there isn't really much of a difference between writing a lambda vs Action, but MethodInvoker seems to be made for a specific purpose. Is it doing anything different?
Both are equally correct, but the documentation for Control.Invoke states that:
The delegate can be an instance of
EventHandler, in which case the sender
parameter will contain this control,
and the event parameter will contain
EventArgs.Empty. The delegate can also
be an instance of MethodInvoker, or
any other delegate that takes a void
parameter list. A call to an
EventHandler or MethodInvoker delegate
will be faster than a call to another
type of delegate.
So MethodInvoker would be a more efficient choice.
For each solution bellow I run a 131072 (128*1024) iterations (in one separated thread).
The VS2010 performance assistant give this results:
read-only MethodInvoker: 5664.53 (+0%)
New MethodInvoker: 5828.31 (+2.89%)
function cast in MethodInvoker: 5857.07 (+3.40%)
read-only Action: 6467.33 (+14.17%)
New Action: 6829.07 (+20.56%)
Call to a new Action at each iteration
private void SetVisibleByNewAction()
{
if (InvokeRequired)
{
Invoke(new Action(SetVisibleByNewAction));
}
else
{
Visible = true;
}
}
Call to a read-only, build in constructor, Action at each iteration
// private readonly Action _actionSetVisibleByAction
// _actionSetVisibleByAction= SetVisibleByAction;
private void SetVisibleByAction()
{
if (InvokeRequired)
{
Invoke(_actionSetVisibleByAction);
}
else
{
Visible = true;
}
}
Call to a new MethodInvoker at each iteration.
private void SetVisibleByNewMethodInvoker()
{
if (InvokeRequired)
{
Invoke(new MethodInvoker(SetVisibleByNewMethodInvoker));
}
else
{
Visible = true;
}
}
Call to a read-only, build in constructor, MethodInvoker at each iteration
// private readonly MethodInvoker _methodInvokerSetVisibleByMethodInvoker
// _methodInvokerSetVisibleByMethodInvoker = SetVisibleByMethodInvoker;
private void SetVisibleByMethodInvoker()
{
if (InvokeRequired)
{
Invoke(_methodInvokerSetVisibleByMethodInvoker);
}
else
{
Visible = true;
}
}
Call to the function cast in MethodInvoker at each iteration
private void SetVisibleByDelegate()
{
if (InvokeRequired)
{
Invoke((MethodInvoker) SetVisibleByDelegate);
}
else
{
Visible = true;
}
}
Example of call for the "New Action" solution :
private void ButtonNewActionOnClick(object sender, EventArgs e)
{
new Thread(TestNewAction).Start();
}
private void TestNewAction()
{
var watch = Stopwatch.StartNew();
for (var i = 0; i < COUNT; i++)
{
SetVisibleByNewAction();
}
watch.Stop();
Append("New Action: " + watch.ElapsedMilliseconds + "ms");
}
I prefer using lambdas and Actions/Funcs:
Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post")));
Action is defined in System, while MethodInvoker is defined in System.Windows.Forms - you may be better off using Action, since it is portable to other places. You will also find more places that accept Action as a parameter than MethodInvoker.
However, the documentation does indicate that calls to delegates of type EventHandler or MethodInvoker in Control.Invoke() will be faster than any other type.
Aside from which namepsace they are in, I don't believe there is a meaningful functional difference between Action and MethodInvoker - they are essentially both defined as:
public delegate void NoParamMethod();
As an aside, Action has several overloads which allow parameters to be passed in - and it is generic so that they can be typesafe.
Also per MSDN:
MethodInvoker provides a simple delegate that is used to invoke a method with a void parameter list. This delegate can be used when making calls to a control's Invoke method, or when you need a simple delegate but do not want to define one yourself.
an Action on the other hand can take up to 4 parameters.
But I don't think there is any difference between MethodInvoker and Action as they both simply encapsulate a delegate that doesn't take a paremter and returns void
If you look at their definitions you'll simply see this.
public delegate void MethodInvoker();
public delegate void Action();
btw you could also write your second line as.
Control.BeginInvoke(new MethodInvoker(DoSomething), null);
It is a matter of preference in most cases, unless you intend to reuse the DoSomething() method. Also the anonymous functions will place your scoped variables on the heap, might make it a more expensive function.
Don't forget to somehow check if control is available at the moment, to avoid errors at closing form.
if(control.IsHandleCreated)
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));