[RESOLVED] How to use Picturebox's Invoke method in C++
The language that I'm using is C++. I have a backgroundworker to prevent my UI from crashing. However, within the background function I need to update my UI. I read that using the control's Invoke will do the trick. However, I can't seem to make it work. The code is as follows:
I'm not completely sure whether I really get what you want to express with that obscure syntax, but if it's setting the picture box' Image property and then call its Update() method, both as cross-thread calls, then it would go like this (assuming the background worker work function and the picture box are members of the same form class instance):
As you're probably not blocking your GUI thread (which probably was at least one of the main reasons why you're using a worker thread in the first place), invoking Update() probably isn't even necessary.
But there's an alternative option here that you may find simpler: While the MSDN documentation superficially suggests that you can only pass a progress percentage and the handle to the object you got passed in via RunWorkerAsync() to the two-paremeter overload of ReportProgress(), in fact this is not the case. For instanxce, I like to pass a per-mille value rather than a percentage value as the first parameter to get more fine-grained progress reporting. But of course it's not limited to that either; you may pass anything that fits into an int.
However, much more important is the second parameter: You may practically pass anything you like though that parameter, in this specific case btmp. You need to observe the principles of thread safety when doing that, but you'd need to do that when using Invoke() as well. Using the progress reporting facility just hides the cross-thread call inside the BackgroundWorker class. One technique I really like to use in that context is passing "fire and forget" packets as that second parameter: Once you passed them to ReportProgress(), never touch them (or any objects directly or indirectly referenced by them) again from inside the worker thread. That way you're always on the safe side regarding potential multithreading issues. And of course, the safest way to ensure that is simply not keeping a handle to the progress packet inside your worker function once you passed it.
I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.
This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.
Many thanks! It's exactly what I need. I think I can't use the ReportProgress() function since I update a lot of GUI controls on the function associated with RunWorkerAsync(). Moreover, do you have an article that explains the syntax of what you showed me because I can't seem to make it work now for RichTextBox. My code is:
I think I can't use the ReportProgress() function since I update a lot of GUI controls on the function associated with RunWorkerAsync().
You're not limited to passing a single instance of one of the already defined .NET framework classes when using that technique. You can define your own progress packet class at will and pass that. For instance, this is a progress packet class from one of my real-life programs:
public ref class ProgressPacket
ProgressPacket() : m_nFileCount(0), m_nDirCount(0)
ProgressPacket(int nFc_, int nDc_) : m_nFileCount(nFc_), m_nDirCount(nDc_)
*this = orig;
void operator=(ProgressPacket ^orig)
m_nFileCount = orig->m_nFileCount;
m_nDirCount = orig->m_nDirCount;
int m_nFileCount, m_nDirCount;
Though it may look somewhat more complex at first sight, this essentially conveys nothing more that two ints.
And this is how I pass it from inside the worker function:
I'm not making use of the percentage parameter here at all, so I'm passing 0 for that.
Moreover, do you have an article that explains the syntax of what you showed me [...].
Actually, what I proposed is mostly based on the MSDN documentation on Control::Invoke() and some experience. I'm not using that really frequently either, so I had to look it up in one of my own programs when writing my post. At the end of the individual method documentation there's a link to a "How to" article which may be more instructive, but chances are it's rather C#-centric like much of the MSDN material.
[...] I can't seem to make it work now for RichTextBox. My code is:
and I get a System.Reflection.TargetParameterCountException: Parameter count mismatch error.
Whell, that's actually a quite tricky one over which I already stumbled myself, and it took me some time to figure that out... This "more than one parameter" overload of Invoke() in fact is a variadic function, which means you can call it with two or more parameters of type Object ^ (except the first one), which essentially can represent any .NET type. Internally, this variable-length parameter list is represented as an array<Object ^>, and instead of passing each parameter to the to-be-invoked method to Invoke() individually, you may also pass the entire parameter list as a single array passed as the second parameter of Invoke().
Now, if you try to invoke a method that way that takes an array of any .NET type as its only parameter, Invoke() misinterprets this array as a parameter list rather than a single array parameter. Consequentially, in your case, it attempts to invoke a RichTextBox::Lines::set() that takes a bunch of string parameters instead of one taking a single string array, and as such a method neither exists nor matches the delegate you passed to Invoke(), it naturally fails. The remedy to prevent this misinterpretation is wrapping up your string array inside a single-element array of string arrays, giving Invoke() what it expects when seeing a single array as the second parameter. Like this: