Invoke Method never returns - c#

I have a thread running, which grabs images from a camera, saves them, and updates the pictureBox to display that bitmap. When I want to exit the application, I set my bool exitApplication to true, but it never returns on the join() call.
public void GrabThread()
{
Bitmap copyBmp;
while (!exitApplication)
{
mImage = m_camera.GrabImage();
SaveImage();
copyBmp = (Bitmap)mImage.bmp.Clone();
if (pictureBox1.InvokeRequired)
{
pictureBox1.Invoke(new MethodInvoker(
delegate ()
{
pictureBox1.Image = copyBmp;
}));
}
else
{
pictureBox1.Image = copyBmp;
}
m_camera.ReleaseImage();
}
}
My Exit code:
exitApplication = true;
threadGrab.Join();
m_camera.Stop();
Close();
When I call Break All from the Debug menu, the Thread hangs at
pictureBox1.Invoke(new MethodInvoker(
delegate ()
{
pictureBox1.Image = copyBmp;
}));
Why? And how can I prevent this? Currently I have to call Abort() on the thread to exit it.

This code deadlocks because pictureBox1.Invoke is trying to execute code in the UI thread. That thread though is blocked by the call to threadGrab.Join();
This can be fixed using async/await. await awaits already executing asynchronous tasks without blocking the way Join() does. When it finishes, execution resumes in the original synchronization context. In a WinForms or WPF application, this means execution resumes on the UI thread.
I assume the only thing that needs to run in the background is m_camera.GrabImage();. In that case, the code could look something like this :
public async void Button1_Click(object sender, EventArgs args)
{
await Task.Run(()=>m_camera.GrabImage();
//Back in the UI thread
SaveImage();
var copyBmp = (Bitmap)mImage.bmp.Clone();
pictureBox1.Image = copyBmp;
m_camera.ReleaseImage();
}
Task.Run will execute m_camera.GrabImage() in a threadpool thread. await will await for this to finish without blocking the UI thread. When it finishes, execution resumes in the UI thread which means there's no need for Invoke.
This could run in a loop too :
public async void Capture_Click(object sender, EventArgs args)
{
while(someCondition)
{
await Task.Run(()=>m_camera.GrabImage();
SaveImage();
var copyBmp = (Bitmap)mImage.bmp.Clone();
pictureBox1.Image = copyBmp;
m_camera.ReleaseImage();
}
}

It may not the right answer but you can using both OnClosing and OnClosed to Stop your camera then close your app, I don't know does it work in Winform but it worked with me in WPF
protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = false; //prevent your application to shutdown
Camera.Stop(); //stop your camera
base.OnClosing(e);
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Application.Current.Shutdown(); //then shutdown again
}
Via 2 step, your camera will stop without Join any thread. And note that this code is written in Wpf, not Winform but I thought you can find a similar way to do in Winform
Hope this answer may help you.

Related

How to close WPF window inside of a Task

I need to run a task to check the connection.
My windows should not be frozen during this check.
So I start the Task, and close my window at the end of this task.
But this returns an exception: InvalidOperationException:'The calling thread cannot access this object because another thread owns it'.
Like this :
private void Window_ContentRendered(object sender, System.EventArgs e)
{
Task.Run(() =>
{
ConnectionState = false;
if (NetworkTools.CheckGlobalConnection() == (ConnectionStatus.NetworkConnectionSuccess, ConnectionStatus.ServerConnectionSuccess))
{
ConnectionState = true;
}
this.Close();
});
}
How do I close my window at the end of the task without freezing it and without having this exception ?
(I have a progress bar that rotates indefinitely)
Or you could just use async await. Task.Run will offload and the await will create a continuation on current SynchronizationContext. In turn giving control back to the UI and closing on the right thread.
private async void Window_ContentRendered(object sender, System.EventArgs e)
{
await Task.Run(() =>
{
ConnectionState = false;
if (NetworkTools.CheckGlobalConnection() == (ConnectionStatus.NetworkConnectionSuccess, ConnectionStatus.ServerConnectionSuccess))
ConnectionState = true;
});
this.Close();
}
Also as noted, Calling ConfigureAwait(false), would not be the right thing to do in this case
Use Dispatcher to queue window closing logic on the unique UI thread.
Something like
Dispatcher.Invoke(
() =>
{
// close window here
});
Whatever is passed into .Invoke(...) as a delegate, is invoked on the UI thread and hence has right to access all UI elements. It is common (and the only correct) way to deal with UI-mutations within non-UI threads.
As an alternate method you can use ContinueWith
private void Window_ContentRendered(object sender, System.EventArgs e)
{
Task.Run(() =>
{
// Your code
}).ContinueWith((tsk) =>
{
this.Close();
}, TaskScheduler.FromCurrentSynchronizationContext());
}

keep windows.forms controls in same Main thread

So, I have a win form that calls a method
dvm.SetVoltage(excitationVoltage, rigNo);
which runs a task in another class
public void SetVoltage(double voltage, int rigNum)
{
Task.Run(() => ReadDVMWorker());
}
Once the worker is finished (voltage set) it triggers an event In the main Form1.cs
private void dvmVoltageSet(object sender, VoltageEventArgs e)
{
VoltageSet = e.VolSet;
TestLvdtNull();
}
Calling TestLvdtNull method:
private void TestLvdtNull()
{
tbMessage.Location = new Point((int)(x / 2 - 250), 150);
}
As soon as the tbMessage line is reached it causes an exception because it has started another thread other than the one tbMessage was created in, how can I prevent it from starting a new thread and continue using the Main thread please?
I have looked at singlethreadsynchronizationcontext, but couldn't make it compile and I know that you can invoke:
tbMessage.Invoke((Action)delegate
{
tbMessage.Location = new Point((int)(x / 2 - 250), 150);
});
But I have many controls with many attributes changing, there must be a way to keep the UI on the main thread?
All UI controls are created at one thread. That is by design in many UI frameworks. After you finish your task you have to return to the UI thread to access UI controls.
One option mentioned in comments is to use async/await where the part of the method after await keyword is executed on the same thread as was before the async method.
// UI thread
await ReadDVMWorker(); // executed at ThreadPool
// UI thread
If you prefer to stay with Task, you can use ContinueWith method with correct TaskScheduler parameter, which ensures that you're back to UI thread. Eg. TaskScheduler.FromCurrentSynchronizationContext()
Async/await attempt code:
private async void button1_Click(object sender, EventArgs e)
{
// Call the method that runs asynchronously.
string result = await WaitAsynchronouslyAsync();
// Display the result.
textBox1.Text += result;
}
//The following method runs asynchronously.The UI thread is not
//blocked during the delay.You can move or resize the Form1 window
//while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
await dvm.SetVoltage(5, rigNo); //Task.Delay(10000);
return "Finished";
}
You could have a method to update arbitrary controls
private void dvmVoltageSet(object sender, VoltageEventArgs e)
{
VoltageSet = e.VolSet;
TestLvdtNull(tbMessage);
TestLvdtNull(tbMessage2);
}
private void TestLvdtNull(Control control)
{
control.BeginInvoke((MethodInvoker)delegate()
{
control.Location += new Point((int)(x / 2 - 250), 150);
});
}
After trying several different ways to solve the problem, I solved the problem by using SynchronizationContext.
This grabs the SyncronizationContext of the thread:
private SynchronizationContext _synchronizationContext;
SynchronizationContext uiContext = SynchronizationContext.Current;
Then after running my task in another class, where previously I was getting an cross thread call exception, I call the method that wants use the same UI thread:
uiContext.Post(MethodToCallOnTheSameUIThread, "string");
After this I can modify and update my textboxes and other controls!
You can check the thread id by:
int id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Thread: " + id);
With thanks to Mike Peretz and his CodeProject

WPF Application Indefinite progress bar doesn't show but processes are running on background

As I got the processes to work I ran onto possibly a Threading problem when I was trying to add a ProgressBar to give the user some clue that the process hasn't crashed. Since this is enough, an Indefinite ProgressBar in just fine for me.
<ProgressBar x:Name="ProcessProgress" Minimum="0" Maximum="100" Visibility="Hidden" IsIndeterminate="False" Width="305" Height="20" Margin="240,214,248,10"></ProgressBar>
I tried to initiate a determinate length progress bar which is not visible before the Start button is clicked :
private void Start_Click(object sender, RoutedEventArgs e)
{
...
//process starts here
var fP = new FileProcessor();
ProcessProgress.IsIndeterminate = true;
ProcessProgress.Visibility = Visibility.Visible;
...
//finally show the progressbar as full when done
ProcessProgress.IsIndeterminate = false;
ProcessProgress.Value = ProcessProgress.Maximum;
}
It just runs the whole process and my bar doesn't show up.
How can I spawn a progress bar during the process ?
The problem is that all of your code runs in the UI thread. The UI has no chance to update itself before the entire process finishes.
You can use Task.Run() to run a heavy job in the background without blocking the UI. You can use the await keyword to await that task to complete without blocking the UI. Once the task completes, you are back in the UI thread where you can modify the UI again.
A quick and dirty fix for this event handler would be :
private async void Start_Click(object sender, RoutedEventArgs e)
{
ProcessProgress.IsIndeterminate = true;
ProcessProgress.Visibility = Visibility.Visible;
...
await Task.Run(()=>
{
//process starts here
var fP = new FileProcessor();
...
});
//We are back in the UI thread, we can modify the UI
ProcessProgress.IsIndeterminate = false;
ProcessProgress.Value = ProcessProgress.Maximum;
}
No need to use Invoke to get back to the UI thread, that's the job of await itself.
A note about async void. It's ONLY meant for event handlers or similar methods. You can't await an async void method which means you can't even get any exceptions if something goes wrong. Asynchronous methods that return nothing should have the async Task signature.
If you want to report progress you can use the IProgress interface and the Progress class as explained here. The Progress class will call a callback or raise an event on the thread it was created. The payload can be any class, not just a percentage
It's best to move the reporting code to separate methods, to keep the button handler clean. The code can look like this :
//The progress class
class FileProgress
{
public string FileName{get;set;}
public int Progress{get;set;}
public string Message{get;set;}
public FileProgress(string fileName,int progress,string message)
{
FileName=filename;
Progress=progress;
Message=message;
}
}
//In the form itself
private void ReportStart()
{
ProcessProgress.IsIndeterminate = true;
ProcessProgress.Visibility = Visibility.Visible;
}
private void ReportEnd()
{
ProcessProgress.IsIndeterminate = false;
ProcessProgress.Value = ProcessProgress.Maximum;
}
private void ReportProgress(FileProgress progress)
{
ProcessProgress.Value =progress.Progress;
PanelStatus.Text = $"Working on {progress.FileName} : {progress.Message}";
}
The event handler can now look like this :
private async void Start_Click(object sender, RoutedEventArgs e)
{
ReportStart();
IProgress<FileProgress> progress=new Progress<FileProgress>(ReportProgress);
...
await Task.Run(()=>
{
//process starts here
var fP = new FileProcessor();
foreach(var file in someFiles)
{
progress.Report(new FileProgress(file,0,"Starting");
//Do some processing
progress.Report(new FileProgress(file,100,"Finished");
}
...
});
//We are back in the UI thread, we can modify the UI
ReportEnd();
}

Task causing strange behavior in form_load event

I have a task that runs in the form_load event of a usercontrol in winforms:
private void ucDeviceInsert_Load(object sender, EventArgs e)
{
System.Threading.Tasks.Task getTBox = System.Threading.Tasks.Task.Run(async () =>
{
await AVeryLongRunningProccess();
});
pbImage.Image = Properties.Resources.Remove;
getTBox.Wait();
pbImage.Image = Properties.Resources.Insert;
btnNext.Visible = true;
tmrDeviceInsert.Enabled = true;
tmrDeviceInsert.Start();
}
private void tmrDeviceInsert_Tick(object sender, EventArgs e)
{
Next();
}
I change the image of the picture box to inform the user the progress of the long running process. That part works fine, however the button doesn't show, and the timer never starts. I've stepped through the code, and I can confirm that it is running without any problems, which makes this even more baffling. Any ideas what would be causing this issue?
Task.Run is for pushing CPU-intensive work off the UI thread. Since you're calling an asynchronous method, I suspect it's not CPU-intensive.
So, you can just use async and await:
private async void ucDeviceInsert_Load(object sender, EventArgs e)
{
pbImage.Image = Properties.Resources.Remove;
await AVeryLongRunningProccess();
pbImage.Image = Properties.Resources.Insert;
btnNext.Visible = true;
tmrDeviceInsert.Enabled = true;
tmrDeviceInsert.Start();
}
Note that at the await, the UI is shown and the user can interact with it (that's the point).
getTBox.Wait() is going to try to complete that task synchronously. Therefore, the rest of the code after it won't happen until after the task completes.
I'd think you don't want your task to run synchronously at all, but rather handle its completion asynchronously, something like this:
getTBox.ContinueWith(() => updateStatusInUI());

C# progressbar IsIndeterminate while exectue a function

I'd like to have a indeterminate progress bar going while I'm doing a function. The problem is that while the function is working the UI freeze until the end so I end up with:
void Button1_Click(object sender, RoutedEventArgs e)
{
progressBar1.IsIndeterminate = true;
Task.Factory.StartNew(() =>
{
scrape();
});
}
The thing is that as for backgroundworker, my scrape function don't trigger. I put just the scrape(); onclick it work just fine. The scarpe is something like:
void scrape()
{
string url = "www.site.com";
var web = new HtmlWeb();
var doc = web.Load(url);
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//p[#class='bio']"))
{
//scrape things
}
progressBar1.IsIndeterminate = false;
}
The progress bar go in indeterminate but the scrape() don't trigger and the bar still in indeterminate state.
Any help?
your probably getting an exception in the code that's running on the background thread.
either catch your exception by registering to
AppDomain.UnhandledException
Or more specifically UnobservedTaskException which is like UnhandledException but specific to exceptions thrown from Tasks.
or make your method async and await the operation in a try catch clause :
async void Button1_Click(object sender, RoutedEventArgs e)
{
progressBar1.IsIndeterminate = true;
try
{
await Task.Factory.StartNew(() =>
{
scrape();
});
}
catch(AggregateException ae)
{}
finally
{
progressBar1.IsIndeterminate = false;
}
}
You should make your scrape method async and then await it in the button1_click and keep the progressBar1.IsIndeterminate = false; call in the button1_click method as you are not allowed to change that from another thread.
You are calling assigning a property from another thread. WPF does things to prevent cross thread accesses like this to keep all the UI logic in the UI thread (the main thread). If you want, you can call a method from the UI thread using a Dispatcher. You can access the dispatcher from any control using myControl.Dispatcher.Invoke(MyMethod).
It's also possible to check if you need to call a method from the dispatcher or not. Use if (myControl.Dispatcher.CheckAccess()). If this value is true, you are on the UI thread and you don't need to invoke from the dispatcher.

Categories