Better understanding of how control.InvokeRequired works - c#

First, I have Windows app with a couple of methods.
One within main Form class:
private void generate_button_Click(object sender, EventArgs e)
{
GenerationThreads nw = new GenerationThreads();
nw.control = testlabel;
// nw.DelegateUpdater();
Thread tr1 = new Thread(new ThreadStart(nw.DelegateUpdater));
tr1.Start();
Thread.Sleep(100);
and two in GenerationThreads class:
public void DelegateUpdater()
{
string envelope = "*Envelope was brought safely.*";
string iterations = "";
for (int x = 1; x <= 3; x++)
{
iterations = iterations + x.ToString() + " iterations done.\n";
PassToLegate(iterations);
Thread.Sleep(400);
}
PassToLegate(iterations + envelope);
}
private void PassToLegate(string text)
{
if (control.InvokeRequired == true)
{
var hat = new Legate(PassToLegate);
string message = text + " (Legate involved)";
control.Invoke(hat, new object[] {message});
}
if (control.InvokeRequired == false)
{
control.Text = text + " (Legate not involved)";
}
}
When DelegateUpdater() is called directly after pressing button, like in commented part - without making a new thread - it just nicely executes three for() spins, displaying them all at once, with an annotation, that Legate wasn't involved at the end - as it's supposed to.
But when a new thread is involved, apart from having said for() display neatly sequenced, I also get both annotations - that the Legate was and wasn't involved.
Why is control.InvokeRequired() acting like true and false at the same time? Why does
if(control.InvokeRequired == false)
{
control.Text = text + " (Legate not involved)";
}
the "text" variable in this particular fragment seem empty? When it's being milled by delegate as "message" - it isn't. And finally, why, after deleting this part of the code completely, the control doesn't show any of the new data at all - even though it was supposed to pass through delegate already? Clearly something about the mechanics still eludes me and I can't put the finger on it. If someone could please explain, what is the real data flow in here.
Thanks!

I also get both annotations - that the Legate was and wasn't involved.
You get both annotations because the code to each is executed.
You first get the " (Legate involved)" annotation because when the PassToLegate() method is first called, the code is executing in the wrong thread. I.e. InvokeRequired returns true. Thus the annotation is appended to the original text value passed to the method.
In that same block of code, you then call control.Invoke(hat, new object[] {message});. And the delegate variable hat has been initialized to new Legate(PassToLegate);. That causes the PassToLegate() method to be called again, but on the UI thread instead. The new message value, i.e. the text value with the " (Legate involved)" annotation appended, is passed as the parameter.
So the method is called a second time, this time on the UI thread. And in that case, the InvokeRequired is now false, and you add the annotation " (Legate not involved)". Since the text parameter passed already had the " (Legate involved)" annotation appended to it, now both annotations are part of the string value assigned to the Text property.
For what it's worth, it is my opinion that the code should never bother with InvokeRequired. It is safe to call Invoke() when you are on the UI thread already (though of course ideally one would never do that), and so the Invoke() method itself has to do the equivalent of checking InvokeRequired anyway. You might as well just always call Invoke() all the time and keep the code simpler.
Even better would be to use higher-level abstractions such as BackgroundWorker, Progress<T>, and async/await (the last one being especially preferable when appropriate). Then you don't need to deal with the Invoke() method at all; the cross-thread invocations are handled automatically for you.

Related

Why when reporting to backgroundworker progresschanged to the progressbar the percentages i'm getting exception?

The code in the progresschanged event:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int eventIndex = 0;
try
{
eventIndex = (int)e.UserState;
}
catch
{
MessageBox.Show(e.UserState == null ? "null" : e.UserState.GetType().FullName);
throw;
}
else if (eventIndex == 4) // percent complete
{
progressBar1.Value = Int32.Parse(stringProgressReport[4]);
}
else
{
throw new Exception("Invalid event index: " + eventIndex);
}
}
Then in the upload event of youtube i have this code:
string failed = "";
double mbSent = 0;
int percentComplete = 0;
VideoProcessingDetailsProcessingProgress vp = new VideoProcessingDetailsProcessingProgress();
private void videosInsertRequest_ProgressChanged(IUploadProgress obj)
{
stringProgressReport[1] = "Uploading";
ulong? ul = vp.TimeLeftMs;
stringProgressReport[1] = obj.Status.ToString();
if (stringProgressReport[1] == "Uploading")
{
fileuploadpercentages = (int)Math.Round(((double)obj.BytesSent) / totalBytes * 100);
stringProgressReport[4] = fileuploadpercentages.ToString();
backgroundWorker1.ReportProgress(0, 4);
stopwatch.Start();
uploadstatus = "uploading file";
}
The first thing is that i see using breakpoint that in the backgroundworker progresschanged event the value the progressbar get is 0.
The second problem is that i'm getting exception on the line:
progressBar1.Value = Int32.Parse(stringProgressReport[4]);
Input string was not in a correct format
Now i see that the variable fileuploadpercentages is on 8 but i'm getting this exception.
When using a breakpoint i see in the variable stringProgressReport:
[0] null
[1] "Uploading"
[2] "0"
[3] "0"
[4] "null"
First why i'm getting the exception if index 4 is "0" ?
Second why the reporting is 0 all the time ?
Without a good, minimal, complete code example that reliably reproduces the problem, it is not possible to explain each detail you are asking about. But certainly some useful things can be said:
First why i'm getting the exception if index 4 is "0" ?
As you can see in the debugger display of stringProgressReport, the value at index 4 is "null", not "0". Trying to parse the string "null" as an Int32 value will throw the exception you are seeing.
The code you posted clearly does assign your percentage calculation to element 4 here:
stringProgressReport[4] = fileuploadpercentages.ToString();
But it is just as obvious the debugger information (which no one here can confirm or refute, lacking a complete code example) indicates that something else has put the value of "null" in that element position.
Unless and until you will share a code example that is consistent with the stated observation, it's not possible to say for sure what is happening.
Note that having thrown an exception, the code will never get far enough to set the ProgressBar.Value property. So it's not much of a surprise it might remain at the value 0.
Second why the reporting is 0 all the time ?
I'm not sure what this question means. It's not reporting 0. It's reporting "null".
Since the code you posted doesn't match the array you posted, I guess it's possible there are other parts of that code that also don't match what you're actually debugging. For example, had you written the fileuploadpercentages computation differently — e.g. by omitting the cast to double before the first division in the expression — then that would explain a computed value of 0.
But again, without a good code example, it's not possible to explain what you say is happening.
I do agree with other comments regarding your code, such as the very strange and very wrong way to pass state from your worker code to the progress event handler and your ignoring the percentProgress parameter of the ReportProgress() method.
I also agree that in general you should not use a blanket catch, but in this case you rethrow the exception so you're not really handling it, so much as simply observing it. The latter is much less of a problem (and in many cases, the right thing to do, though showing a message box in the middle of unwinding the stack is not necessarily the best idea in the world :) ).

Visual Studio during Debugging: The function evaluation requires all threads to run

I'm suddenly getting a strange error while debugging. Up to now the variable in the watch windows has been showing correctly. Now I am always getting this error message in the watch windows:
The function evaluation requires all threads to run
I am not able to check any variable anymore. I am not explicitly working with threads. What can I do to get it working again?
I already disabled, as mentioned in some forums, the function: "Enable property Evaluation and other implicit function Calls" in the option window of the debugger. But without success, and it gives me this error:
Error Implicit Function evaluation disabled by the user
From the msdn forum:
This isn't an error in and of itself, but more of a feature of your debugger.
Some properties require code to be executed in order for the property to be read, but if this requires cross-thread interaction, then other threads may have to run as well. The debugger doesn't do this automatically, but certainly can, with your permission.
Just click the little evaluate icon and it will run your code and evaluate the property.
For further details on this behaviour check this excelent article
I ran into this issue when just trying to get items from a table called "AGENCY" using Entity Framework:
var agencies = db.AGENCY.OrderBy(e => e.FULLNAME);
Hovering over agencies in debug mode, clicking to expand the options, and clicking Results would give the dreaded "The function evaluation requires all threads to run" with a "Do Not Enter" icon at the end that, on which, clicking did nothing.
2 possible solutions:
Add .ToList() at the end:
var agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
List<AGENCY_TABLE> agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
Credit goes to Hp93 for helping me come to this solution. In the comments on MUG4N's answer where I found this solution, it also mentions trying .Any() instead of .ToList(), but this gives a Boolean instead of a <T>, like <AGENCY> is, so it probably wouldn't help.
Workaround - try a different path in the debug options. I found that I could click on the "Non-Public Members" > "_internalQuery" > ObjectQuery > Results View and get my values that way.
MUG4N has indeed provided a correct answer however if you hover over the line of code in debug, you may be looking at something like the below. If so, click the little re-evaluate icon highlighted in the image below...
NB: I obtained this image by pinning, normally the re-evaluate icone are in the middle of the window and not down the left hand column.
You should make thread safe call because accessing Windows form controls are not Thread safe in multithreading.
This is my simple code which makes Thread safe call and sets Progress bar.
public partial class Form1 : Form
{// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void StringArgReturningVoidDelegate(string text);
private Thread demoThread = null;
public int Progresscount = 0;
static EventWaitHandle waithandler = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
}
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
{
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
}
catch
{
return false;
}
}
public void Progressincrement()
{
waithandler.WaitOne();
while (CheckForInternetConnection()==true)
{
if (Progresscount==100)
{
break;
}
SetLabel("Connected");
Progresscount += 1;
SetProgress(Progresscount.ToString());
Thread.Sleep(TimeSpan.FromSeconds(1));
}
if (Progresscount <100)
{
Startthread();
}
SetLabel("Completed");
}
public void Startthread ()
{
this.demoThread= new Thread(new ThreadStart(Progressincrement));
this.demoThread.Start();
SetLabel("Waiting for connection");
while (CheckForInternetConnection() == false) ;
waithandler.Set();
}
private void SetLabel(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.label1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetLabel);
this.Invoke(d, new object[] { text });
}
else
{
this.label1.Text = text;
}
}
private void SetProgress(string Value)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.progressBar1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetProgress);
this.Invoke(d, new object[] {Value});
}
else
{
this.progressBar1.Value = Convert.ToInt32(Value);
}
}
private void Form1_Load(object sender, EventArgs e)
{
Startthread();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Responsive");
}
}
For more information MSDN
This isn't an error, but more of a feature of your debugger.
The debugger doesn't do this automatically, but certainly can, with users permission. Just click the little space icon and it will run the code and evaluate the property.
I use the next workaround to pass:
var OtherThreadField = "";
Invoke(new MethodInvoker(delegate
{
OtherThreadField = ExecuteNeededMEthod();
}));
Now i have a value for OtherThreadField.
I faced the same issue and solved .The Issue arise due to username and password ,in SQL connection there is user and password but in code there no user and password. so I enable the user and the password and the issue solved
For me, this happened when trying to break on a line that accesses a complex object instance contained by a Settings Class.
A breakpoint on the following if results in Settings.Default.FindSettings with the value being "The function evaluation requires all threads to run." If I press the force eval button, it is null. Stepping with the force eval button click or not enters the if block and initializes the object. If I remove the breakpoint and add a new breakpoint following the if block, the Settings.Default.FindSettings deserializes properly with the expected values.
if (Settings.Default.FindSettings == null)
{
Settings.Default.FindSettings = new FindSettings();
}
After trial and error, I added the following code before the above if block to access the settings prior to breaking. This seems to reliably fix the problem. I do not need it in production so I wrap in conditional compiler directive. I have a comment in the code instead of a non-descript discard:
#if DEBUG
var _ = Settings.Default.FindSettings;
#endif
I am not sure if the above line would be optimized out in production since it has side effects. As I only need it while debugging, I have not checked.

C# WUApiLib - Download and Install Asynchronously

I am programming using the WUApiLib library from Microsoft. I have written a simple application that searches for all software updates that are not installed and then downloads and installs them. This part is working perfectly (I used the code found here to help: http://www.nullskull.com/a/1592/install-windows-updates-using-c--wuapi.aspx).
However, I want to make use of the BeginDownload, EndDownload, BeginInstall, EndInstall functionality of the library so that it can report progress back to the interface. The functions in that article are synchronous and the functions I mention are asynchronous.
I am using the first answer on this page as a template:
C# and WUAPI: BeginDownload function
However, my Invoke() function is never getting called and I can't figure out why.
iUpdateDownloader_onProgressChanged progress = new iUpdateDownloader_onProgressChanged(this);
IDownloadJob downloadJob = downloader.BeginDownload(progress, new iUpdateDownloader_onCompleted(this), new iUpdateDownloader_state(this));
public class iUpdateDownloader_onProgressChanged : IDownloadProgressChangedCallback
{
private frmMain form1;
public iUpdateDownloader_onProgressChanged(frmMain mainForm)
{
this.form1 = mainForm;
}
// Implementation of IDownloadProgressChangedCallback interface...
public void Invoke(IDownloadJob downloadJob, IDownloadProgressChangedCallbackArgs e)
{
decimal bDownloaded = ((e.Progress.TotalBytesDownloaded / 1024) / 1024);
decimal bToDownloaded = ((e.Progress.TotalBytesToDownload / 1024) / 1024);
bDownloaded = decimal.Round(bDownloaded, 2);
bToDownloaded = decimal.Round(bToDownloaded, 2);
form1.setDownloadProgressText("Downloading Update: "
+ e.Progress.CurrentUpdateIndex
+ "/"
+ downloadJob.Updates.Count
+ " - "
+ bDownloaded + "Mb"
+ " / "
+ bToDownloaded + "Mb");
}
}
I can put a breakpoint on the first line in the Invoke function and it never reaches there.
Any ideas?
First thing I notice that's wrong: the call to form1.setDownloadProgressText is a call to the UI made from a different, asynchronous thread. You'll want to wrap that in a this.Invoke (if WinForms) or Dispatcher.Invoke (if WPF) to marshall the UI manipulation to the UI thread.
Also, the "this" variable is not available in the list of member variable declarations that occur before the constructor function, so
iUpdateDownloader_onProgressChanged progress = new iUpdateDownloader_onProgressChanged(this);
IDownloadJob downloadJob = downloader.BeginDownload(progress, new
iUpdateDownloader_onCompleted(this), new iUpdateDownloader_state(this));
isn't going to work unless it's wrapped in a constructor or form load event handler, which isn't pictured here.
MY GUESS IS THAT YOUR onState OBJECT IS GETTING INVOKED BEFORE THE ONE SHOWN HERE, AND IT IS ATTEMPTING TO MANIPULATE THE FORM FROM A THREAD OTHER THAN THE UI ONE, AND THIS BLOW-UP IS PREVENTING THE OTHER OBJECTS (INCLUDING THE ONE DEPICTED HERE) FROM EVER BEING INVOKED.

Why would this progress bar code cause the progress bar to "hang"?

In the legacy code I'm working on, there are several file retrieval steps - first this set of data, then that set of data, which update a progress bar with a label displaying which portion of the process is currently active, and the progress bar itself, of course, updates its position. One portion of all this is hanging, though, and via the use of MessageBox.Show()s (I have to do it this way, can't step through it in the debugger), I've narrowed down where the hanging is occurring, but can't figure out why it's occurring.
Warning: the following code is unorthodox and may well warrant such warning signage as "Here be Dragons" or "This way lies madness." Proceed at your own risk/beware of the peril.
MessageBox.Show("Made it just before the pbDialog code");//<-- it hangs after this is displayed
using (pbDialog = new pbDialogs())
{
ProgressBar = new frmProgress( this, true);
ProgressBar.SetProgressLabelText("Vendor/Dept/Expense Data");
typeProgress = (int)ProgressStates.ProgressQRY;
ProgressBar.label1.Text += " (Receiving)";
if( pbDialog != null )
{
pbDialog.ShowDialog( ProgressBar, this );
}
else
{
ProgressBar.ShowDialog();
}
ProgressBar = null;
evt.Set();
}
MessageBox.Show("Made it just after the pbDialog code"); //This is not seen
pbDialog is declared in the same form as this code snippet:
public pbDialogs pbDialog;
pbDialogs is a class in another form (frmProgress.cs):
public class pbDialogs : IDisposable
ProgressBar is an instance of the anonymous class defined in frmProgress.cs (frmProgress, that is to say, which derives from System.Windows.Forms.Form)
public static frmProgress ProgressBar;
typeProgress is a locally defined int:
public static int typeProgress = 0;
evt is the name of the arg passed into the method from which this snippet originates:
private void FetchVendorDepartmentData(ManualResetEvent evt)
ManualResetEvent, as you may know, is a member of System.Threading
Does anybody see anything eyebrow-raising here (besides the general unorthodoxy of it all)?
UPDATE
I added more messages:
MessageBox.Show("Made it just before the pbDialog code");//<-- it hangs after this. TODO: Remove before deploying
using (pbDialog = new pbDialogs())
{
MessageBox.Show("Made it just before ProgressBar = new frmProgress");// TODO: Remove
ProgressBar = new frmProgress( this, true);
MessageBox.Show("Made it just after ProgressBar = new frmProgress");// TODO: Remove
ProgressBar.SetProgressLabelText("Vendor/Dept/Expense Data");
typeProgress = (int)ProgressStates.ProgressQRY;
MessageBox.Show("Made it just after assignment to typeProgress");// TODO: Remove
ProgressBar.label1.Text += " (Receiving)";
if( pbDialog != null )
{
MessageBox.Show("pbDialog was not null");// TODO: Remove
pbDialog.ShowDialog( ProgressBar, this );
}
else
{
MessageBox.Show("pbDialog was null");// TODO: Remove
ProgressBar.ShowDialog();
}
ProgressBar = null;
MessageBox.Show("ProgressBar set to null");// TODO: Remove
evt.Set();
MessageBox.Show("evt.Set called");// TODO: Remove
}
MessageBox.Show("Made it just after the pbDialog code");//TODO: Remove
}
...and the last one I see is, "pbDialog was not null"
UPDATE 2
In accord with the answer from "500 - Internal Server Error," I prepended a line to show the ProgressBar:
ProgressBar.ShowDialog();
if( pbDialog != null ) . . .
...but it makes no diff; in fact, with that I don't even make it as far as without it - I don't see the "pbDialog was not null" message.
Apologies in advance to Billy Blake, but: What the hammer? What the chain? What the anvil? What dread grasp is going on here?
UPDATE 3
So apparently either of these lines cause the hang:
ProgressBar.ShowDialog(); // with this, "pbDialog was not null" is not seen
pbDialog.ShowDialog( ProgressBar, this ); // if make it to here (line above commented out), "ProgressBar set to null" is not seen.
UPDATE 4
The problem may not be in this code after all, as I found another spot in the same class that uses the exact same code, and that portion of the data retrieval completes just fine...
You are specifying that you want ProgressBar as the modal owner of pbDialog here:
pbDialog.ShowDialog( ProgressBar, this );
but it doesn't look like you've actually shown ProgressBar (the owner) yet at this point.

A little help needed catching events being raised inside a seperate thread

To begin, I'm working on a pretty high level file system where I need to be able to (with very pin point accuracy) identify and process files in a timely manner. With that said, I am working on a system that will be using the FileSystemWatcher. The whole problem with the watcher though is the fact that it tends to have issues when throwing events when there are large files involved.
To remedy this I'm working on an abstract class that can handle the files individualy once they are created by the file system watcher.
The current road block that I am running into is that my out of process validation on the file is throwing an event, I'm just having problems catching it.
public abstract class absFile
{
public delegate void FileAvailable(object sender, FileEventArgs e);
public event FileAvailable OnFileAvailable;
public void isAvailable()
{
// Create a new threaded instance of the AvailableCheck private void
// This method will be run out of process to allow other operations to continue.
Thread toAvailableCheck = new Thread(new ThreadStart(AvailableCheck));
// Once the threaded object is created, start it.
toAvailableCheck.Start();
}
private void AvailableCheck()
{
// Declaring the file stream toThisFile to be used later with the File.Open
FileStream toThisFile;
// Declaring and instantiating the attempt counter for the loop
int tiAttemptNumber = 0;
// Declaring the event args for returning the events that are
// used by this object.
FileEventArgs toFileEventArgs = new FileEventArgs();
do {
try
{
// Attempt to open the file. If this fails the try
// will interrupt the processing and it will be caught.
toThisFile = File.Open(this.FilePath, FileMode.Open);
// If the file.open method does not fail, the isFileAvailable
// property will be set to true by updating the mbIsAvailable
// private boolean.
mbIsAvailable = true;
// populate the file event args to send back
// the number of attempts made at the file and the pause lenght
toFileEventArgs.Attempts = tiAttemptNumber;
toFileEventArgs.Pause = this.AttemptPause / 1000;
// This event is called when the file is complete.
// The client application will be able to handle this event.
OnFileAvailable(this, toFileEventArgs);
// close and dispose of the filestream.
toThisFile.Close();
toThisFile.Dispose();
}
catch (Exception toException)
{
// Since the open failed, add 1 to the counter so that
// it will eventually time out.
tiAttemptNumber++;
// Set the isFileAvailable property to false. This property
// will default as false, but as a part of standard, make sure that
// if the open fails that the flag IS set to false by updating the
// mbIsAvailable private boolean.
mbIsAvailable = false;
// Put the thread to sleep for the ammount of time specified
// by the AttemptPause. This will give the file time to finish
// whatever process it is involved in.
Thread.Sleep(this.AttemptPause);
}
// Continue to make attempts until either the file is marked as available
// or the number of current attempts is the same as or greater than the
// AccessAttempts property.
} while (!this.isFileAvailable && this.AccessAttempts > tiAttemptNumber);
}
this is the code that I am running as you can see in the private void AvailableCheck, OnfileAvailable is the delegate called passing back this and the file event args.
now i have inherited this abstract class, and i need to be able to catch that event.
toWatcher.Created += new FileSystemEventHandler(OnCreated);
is called in the main and farther down the code is the following method
private void OnCreated(object source, FileSystemEventArgs e)
{
lstStatus.Invoke(new MethodInvoker(delegate {
lstStatus.Items.Add(DateTime.Now.ToString("g") + " - " + e.Name + " - File Created Event Detected for: " + e.FullPath);
lstStatus.TopIndex = lstStatus.Items.Count - 1;
tgtFile ThisFile = new tgtFile(e.FullPath);
lstStatus.Items.Add(DateTime.Now.ToString("g") + " - " + e.Name + " - Creating tgtFile Object");
}));
}
The instatiation of the tgtFile object is passed the path which makes its way down the pike to the is available method.
as you can see the chance exists for the OnFileAvailable event to be fired from the tgtFile object.
Also as you can see, the the possibility for multiple tgtFile objects to exist in memory at the same time is there as well based on the threading design of the filesystemwatcher.
in my main application then i want to be able to do something like:
public tgtFile ThisFile;
ThisFile.OnFileAvailable += new EventHandler(OnFileAvailable);
but the EventHandler errors out, and that is where I am stuck.
If it is giving you a compiler error, it's probably because your "OnFileAvailable" method referenced in this line (from the bottom of your post):
ThisFile.OnFileAvailable += new EventHandler(OnFileAvailable);
is not expecting an EventHandler - it's expecting a FileAvailable delegate. Change it to:
ThisFile.OnFileAvailable += new absFile.FileAvailable(OnFileAvailable);
//note that this can also just be ThisFile.OnFileAvailable += OnFileAvailable;
and make sure OnFileAvailable looks like this:
public void OnFileAvailable(object sender, FileEventArgs e)
{
//...
}
First things first... Ensure the event is subscribed, before calling it. Wrap the event call in an IF statement:
if (OnFileAvailable != null)
OnFileAvailable(this, toFileEventArgs);

Categories

Resources