Control.InvokeRequired changing throughout a method - c#

Look at these screenshots. First shows a breakpoint in my code and shows current value of InvokeRequired.
Seconds screenshot shows value of InvokeRequired after pressing F10 (step over) one time in debugger (IF statement content is not entered, ELSE is).
What happens next, is InvalidOperationException on rtbOutput, because I try to change its fields in ReportProgress. Here is how I call OnProgressReported:
public event EventHandler<BuildProgressEventArgs> BuildProgresReported = delegate { };
public void InvokeReportBuildProgress(BuildProgress progress)
{
BuildProgresReported.Invoke(this, new BuildProgressEventArgs(progress));
}
How is this even possible? Is there other, better way to detect if Invoke should be called?
Update:
I have changed method code to the following:
public void OnProgressReported( object caller, BuildProgressEventArgs progressEventArgs )
{
if( rtbOutput.InvokeRequired )
{
Debug.WriteLine($"Invoke was required on thread: #{Thread.CurrentThread.ManagedThreadId} named '{Thread.CurrentThread.Name}'");
rtbOutput.BeginInvoke( new Action( () => OnProgressReported(caller, progressEventArgs) ) );
}
else
{
Debug.WriteLine($"Invoke was NOT required on thread: #{Thread.CurrentThread.ManagedThreadId} named '{Thread.CurrentThread.Name}'");
if ( this.IsDisposed )
{
throw new InvalidOperationException( "This form has been disposed" );
}
rtbOutput.Text = "abc";
rtbOutput.Text = "xxx";
//ReportProgress(progressEventArgs.Progress);
}
}
The only output is
Invoke was NOT required on thread: #15 named ''
and the method this throw an exception on line rtbOutput.Text = "abc";
HOWEVER! When the line rtbOutput.Text = "xxx"; is commented out, everything works fine, even though rtbOutput.Text = "abc"; is still present!
Update #2 - solution:
The problem was a window handle that was not yet created (I subscribe to an event right AFTER creating the window) I have to wait for handle to be created using
this.IsHandleCreated

Related

Task.ConfigureAwait behavior after UI cross-thread operation exception

I was playing with Task.ConfigureAwait in order to better understand what is going beyond the hood. So i got this strange behavior while combining some UI access stuff with the ConfigureAwait.
Below is the sample app using a simple windows form, with 1 Button followed by the test results:
private async void btnDoWork_Click(object sender, EventArgs e)
{
List<int> Results = await SomeLongRunningMethodAsync().ConfigureAwait(false);
int retry = 0;
while(retry < RETRY_COUNT)
{
try
{
// commented on test #1 & #3 and not in test #2
//if(retry == 0)
//throw new InvalidOperationException("Manually thrown Exception");
btnDoWork.Text = "Async Work Done";
Logger.Log("Control Text Changed", logDestination);
return;
}
catch(InvalidOperationException ex)
{
Logger.Log(ex.Message, logDestination);
}
retry++;
}
}
Now after button Click:
Test 1 Log results : (Exactly as the above code)
1. Cross-thread operation not valid: Control 'btnDoWork' accessed from a thread other than the thread it was created on.
2. Control Text Changed
Test 2 Log results : (Manual exception throw uncommented)
1. Manually thrown Exception
2. Cross-thread operation not valid: Control 'btnDoWork' accessed from a thread other than the thread it was created on.
3. Control Text Changed
Test 3 Log results : (Same as 1 but without a debugger)
1. Control Text Changed
So the questions are:
Why does the first UI Access (Cross-Thread
Operation) have the next iteration of the loop execute on the Main
Thread ?
Why doesn't the manual exception lead to the same behavior ?
Why does executing the above sample without a debugger attached (directly from exe)
doesn't show the same behavior ?
This one got me scratching my head a bit, but finally found the trick.
The code of the setter of the Button.Text property is:
set
{
if (value == null)
value = "";
if (value == this.Text)
return;
if (this.CacheTextInternal)
this.text = value;
this.WindowText = value;
this.OnTextChanged(EventArgs.Empty);
if (!this.IsMnemonicsListenerAxSourced)
return;
for (Control control = this; control != null; control = control.ParentInternal)
{
Control.ActiveXImpl activeXimpl = (Control.ActiveXImpl) control.Properties.GetObject(Control.PropActiveXImpl);
if (activeXimpl != null)
{
activeXimpl.UpdateAccelTable();
break;
}
}
}
The line throwing the exception is this.WindowText = value; (because it internally tries to access the Handle property of the button). The trick is that, right before, it sets the text property in some kind of cache:
if (this.CacheTextInternal)
this.text = value;
I'll be honest, I have no clue how this cache works, or when it is activated or not (turns out, it seems to be activated in this precise case). But because of this, the text is set even though the exception was thrown.
On further iterations of the loop, nothing happens because the property has a special check to make sure you don't set the same text twice:
if (value == this.Text)
return;
If you change your loop to set a different text every time, then you'll see that the exception is thrown consistently at each iteration.

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.

Custom Message Box displays after Message box

I have some code that when I call my CustomMessageBox it displays the box with a user prompt for an amount of my object to add, once that is done I have it added to a list of objects. Once added, it then Displays a MessageBox.Show to just let the user know it was added.
My problem is that when I run the code it executes all the code, bypasses the display of the Custom message box, then displays the MessageBox.Show, and THEN displays the CMB.Show. I ran the code through the debugger and followed the trail and it hits the CMB.Show before the MessageBox.Show, but is displayed once the code is done. Sorry, I am still learning and might not be telling the problem well, please let me know if there is anything I can further explain upon.
Some code:
private int BasicLand(Card basicLand)
{
var countBox = new TextBox
{
Name = "count",
Width = 100,
};
var cmbCount = new CustomMessageBox
{
Caption = "Blah",
Content = countBox,
RightButtonContent = "ok",
};
cmbCount.Dismissed += (s1, e1) =>
{
switch (e1.Result)
{
case CustomMessageBoxResult.RightButton:
if (int.TryParse(countBox.Text, out tempInt) && Convert.ToInt32(countBox.Text) > 0)
{
countReturn = Convert.ToInt32(tempInt);
break;
}
else
{
//Some code for error....
}
}
};
cmbCount.Show();
return countReturn;
}
Then the other part that triggers first but is last in the code block.
MessageBox.Show("Object was added to List!");
I tried adding the ShowDialog to the custom box but it came up broken in VS. BasicLand is called within another method and when the object is added to the list it will display the MessageBox.Show.
The problem with your code is, it does not take into account that any user interaction is asynchronous. When you call Show() it will actually show the messagebox, but it will not block your currently running thread, the other statements after the call to Show() will be executed immediately and thus your method returns a returnvalue that has not been provided by the user but is just the default. To fix this you have to write your code in continuations.
private void PromtUserForFeeblefezerAmount(Action<int> continueFeeblefzing, Action cancel)
{
var messagebox = CreateFeeblefezerPromt();
messagebox.Dismissed += (sender, args) =>
{
if ( args.Result == CustomMessageBoxResult.RightButton )
continueFeeblefzing( GetFeeblefezerAmount(messagebox) );
else
cancel();
};
messagebox.Show();
}

InvalideOperationException / invoke

the following code is used to trigger invoke (code is reduced, i left out the error handling in this example to make it more clear)
public static void InvokeIfNecessary(this Control control, MethodInvoker methodInvoker)
{
if (control != null && !control.IsDisposed && !control.Disposing)
{
if (control.InvokeRequired)
{
control.Invoke(methodInvoker);
}
else
{
methodInvoker();
}
}
}
Normally it works fine, but sometimes if i call a method of a Form an InvalidOperationException is given. Schematic method to be called
// in a Frm2:
internal void UpdateSomething()
{
List<NO> myObjects = frmMain.NO.GetNOs();
if (null != myObjects)
{
this.InvokeIfNecessary(() =>
{
layoutControlGroup.BeginUpdate(); // DevExpress Layoutcontrolgroup
foreach (NO aObject in myObjects)
{
if(...) // if already a control for the object exist update it.
{
// update
}
else
{
// add item
LayoutControlItem layoutControlItem = new LayoutControlItem();
// create new control
Control control = CreateNewControl(aObject);
layoutControlItem.Control = control;
// do some stuff with visibility and size of control
...
layoutControlGroup.AddItem(layoutControlItem); // <-- And here the InvalidOperationException occurs.
/// The message is (translated
/// InvalidOperationException was not handled by usercode
/// The acces on the Control FrmMain was done from another Thrad then the thread which created it.
...;
}
}
...;
layoutControlGroupCA.EndUpdate();
});
}
}
Well... I must admit that i have a conceptual problem here.
Why is the Exception thrown here?
The Frm2 method creates a new element (In NO there is only a string and a struct with strings and bool). The element is only accessed within the UpdateSomething() method. The layOutControlGroup is a member of Frm2.
So in my opinion only a new Control which shoudl be created in Frm2 Thread should be attached to a Frm2 specific Control.
So why does it insisting in FrmMain? (the main form, which calls the method of the form to inform about an update of items)
P.S. this.InvokeIfRequired <- this is Frm2 actually...
So, as we see, there are always trouble with ( begin) invoke.
Use BeginInvoke instead. is my hint.
Usually it says, that begin invoke on controls executes a method in the same thread where the handle was created on.
But as it seems, the handle of form2 is not been created in the same thread, OR perhaps it is not present yet.
Try to check this and verify this, please.
Ah. by the way, flag exceptions, clr, in visual studio, when they are thrown. This helps to spot the error.
I think that you checked InvokeRequired with a wrong control.
What you needed to check with InvokeRequired is layoutControlGroup, but your extension method checks on form's with the code this.InvokeIfNecessary where this is Frm2.
Also, you invoked layoutControlGroup.BeginUpdate() but layoutControlGroupCA.EndUpdate(), seems not symmetric of the usage.
A correction of the code might be:
internal void UpdateSomething() {
var myObjects=frmMain.NO.GetNOs();
if(null!=myObjects) {
MethodInvoker beginUpdate=() => layoutControlGroup.BeginUpdate();
MethodInvoker endUpdate=() => layoutControlGroup.EndUpdate();
layoutControlGroup.InvokeIfNecessary(beginUpdate);
foreach(NO aObject in myObjects)
if(SomeCondition) {
// update
}
else {
LayoutControlItem layoutControlItem=new LayoutControlItem();
Control control=CreateNewControl(aObject);
layoutControlItem.Control=control;
MethodInvoker addItem=
() => {
layoutControlGroup.AddItem(layoutControlItem);
};
layoutControlGroup.InvokeIfNecessary(addItem);
}
layoutControlGroup.InvokeIfNecessary(endUpdate);
}
}

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.

Categories

Resources