C# this.Invoke broken, process classes event in GUI on different thread - c#

I tried to dive into multithreading once again and hit the ground quite fast (.Net 4.5).
I have a class library, which does some heavy byte-reading from files, raising an event.
public class cMyClass
{
public event EventHandler<cUpdateEventArgs> OnReadUpdate = delegate{ };
public int id {get; private set;}
public cMyClass(int in_id)
{ id = in_id; }
public async void ReadFromFile(string in_filePath)
{ // Do a bit of reading all bytes here and error-checking there...
//Here comes the heavy lifting
await ReadTriangles(stlBytes.SubArray(cConstants.BYTES_IN_HEADER, stlBytes.Length - cConstants.BYTES_IN_HEADER));
}
private Task ReadTriangles(byte[] in_triangles)
{
UInt32 numberOfTriangles = BitConverter.ToUInt32(cHelpers.HandleLSBFirst(in_triangles.SubArray(0, 4)), 0);
float percentage = 0;
float percentageOld = percentage;
OnReadUpdate(this, new cReadUpdateEventArgs(id, Resources.Texts.ReadingTriangles, percentage));
for (UInt32 i = 0; i < numberOfTriangles; i++)
{
percentage = ((float)(i + 1)) / numberOfTriangles * 100;
triangleList.Add(new cSTLTriangle(in_triangles.SubArray(Convert.ToInt32(i * cConstants.BYTES_PER_TRIANGLE + 4), Convert.ToInt32(cConstants.BYTES_PER_TRIANGLE))));
if (percentage - percentageOld >= 0.1) //Just tell about .1-percentage increases
{
percentageOld = percentage;
OnReadUpdate(this, new cReadUpdateEventArgs(id, Resources.Texts.ReadingTriangles, percentage));
}
}
OnReadUpdate(this, new cReadUpdateEventArgs(id, Resources.Texts.ReadingTriangles, percentage));
return Task.FromResult<bool>(true);
}
}
As you can see, any instance of cMyClass would run the ReadFromFile Task on a different thread. So naturally - wanting to be thread-safe - I have to do some Invoking. But wait!
Moving on to a WindowsForms-Application is where things start to go wrong. I have a testing form with just two progressBars and a button.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
progressBar1.Minimum = 0;
progressBar1.Maximum = 1000;
progressBar2.Minimum = 0;
progressBar2.Maximum = 1000;
//Now the same code as from the console application:
cSTLBinaryDataModel stlFile = new cSTLBinaryDataModel(1);
cSTLBinaryDataModel stlFile2 = new cSTLBinaryDataModel(2);
stlFile.OnReadUpdate += stlFile_OnReadUpdate;
stlFile2.OnReadUpdate += stlFile_OnReadUpdate;
List<Task> taskList = new List<Task>();
taskList.Add(new Task(new Action(() => stlFile.ReadFromFile(#"C:\temp\Test.stl"))));
taskList.Add(new Task(new Action(() => stlFile2.ReadFromFile(#"C:\temp\Test.stl"))));
foreach (Task t in taskList)
t.Start();
// I need Task.WaitAll to re-enable the button after all processing is done
Task.WaitAll(taskList.ToArray());
button1.Enabled = true;
}
private void stlFile_OnReadUpdate(object sender, cReadUpdateEventArgs e)
{
switch (e.id)
{
case 1:
progressBar1.BeginInvoke(new Action(() =>
progressBar1.Value = Convert.ToInt32(e.percentage * 10)));
break;
case 2:
progressBar2.BeginInvoke(new Action(() =>
progressBar2.Value = Convert.ToInt32(e.percentage * 10)));
break;
}
}
}
This works in so far, that the files are being processed in the background (I checked the Task manager) but the Task.WaitAll blocks my UI, so after everything is done, I can see the progressBars running up.
How can I wait for the Tasks to finish but at the same time keep the UI responsive?

I tried to dive into multithreading once again...
Multithreading is totally old-school. These days, for I/O-bound opeations, use async/await and the patterns that go along with it (i.e., IProgress<T> for progress updates). You'll find your life a lot easier.
These principles will help:
Write synchronous code if the code is synchronous, and only use async/await if the code is asynchronous. In the code you posted, ReadTriangles should not have an asynchronous signature.
Get rid of the event. Cross-thread events are messy. Instead, use IProgress<T>.
Avoid async void; use async Task instead.
Here's how your class would look with these principles in place:
public async Task ReadFromFileAsync(string in_filePath, IProgress<cUpdateEventArgs> progress)
{
// Do a bit of reading all bytes here and error-checking there...
//Here comes the heavy lifting
ReadTriangles(stlBytes.SubArray(cConstants.BYTES_IN_HEADER, stlBytes.Length - cConstants.BYTES_IN_HEADER), progress);
}
private void ReadTriangles(byte[] in_triangles, IProgress<cUpdateEventArgs> progress)
{
UInt32 numberOfTriangles = BitConverter.ToUInt32(cHelpers.HandleLSBFirst(in_triangles.SubArray(0, 4)), 0);
float percentage = 0;
float percentageOld = percentage;
if (progress != null)
progress.Report(new cReadUpdateEventArgs(id, Resources.Texts.ReadingTriangles, percentage));
for (UInt32 i = 0; i < numberOfTriangles; i++)
{
percentage = ((float)(i + 1)) / numberOfTriangles * 100;
triangleList.Add(new cSTLTriangle(in_triangles.SubArray(Convert.ToInt32(i * cConstants.BYTES_PER_TRIANGLE + 4), Convert.ToInt32(cConstants.BYTES_PER_TRIANGLE))));
if (percentage - percentageOld >= 0.1) //Just tell about .1-percentage increases
{
percentageOld = percentage;
if (progress != null)
progress.Report(new cReadUpdateEventArgs(id, Resources.Texts.ReadingTriangles, percentage));
}
}
if (progress != null)
progress.Report(new cReadUpdateEventArgs(id, Resources.Texts.ReadingTriangles, percentage));
}
And here's one way you could use it. Note the use of Task.Run in the UI layer to push the CPU-bound work off the UI thread:
cSTLBinaryDataModel stlFile = new cSTLBinaryDataModel(1);
cSTLBinaryDataModel stlFile2 = new cSTLBinaryDataModel(2);
var progress = new Progress<cReadUpdateEventArgs>(update =>
{
switch (update.id)
{
case 1:
progressBar1.Value = Convert.ToInt32(update.percentage * 10);
break;
case 2:
progressBar2.Value = Convert.ToInt32(update.percentage * 10);
break;
}
});
await Task.WhenAll(
Task.Run(() => stlFile.ReadFromFileAsync(#"C:\temp\Test.stl", progress)),
Task.Run(() => stlFile2.ReadFromFileAsync(#"C:\temp\Test.stl", progress)));
button1.Enabled = true;

Of course the UI doesn't update if you call Task.WaitAll. This stops the UI thread until all tasks are finished.
One way to go could be: For every task you start, increment a private volatile int runningTasks variable. Whenever a task finishes, call another event. In the handler for that event
Decrement the variable again
When it reaches 0, activate the button again
You need to decide whether you want to be fully asynchronous or fully synchronous.
Example:
private volatile int runningTasks = 0;
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
runningTasks = 2;
...
stlFile.OnReadUpdate += stlFile_OnReadUpdate;
stlFile2.OnFinished += stlFile_OnFinished;
stlFile.OnReadUpdate += stlFile_OnReadUpdate;
stlFile2.OnFinished += stlFile_OnFinished;
List<Task> taskList = new List<Task>();
taskList.Add(...);
taskList.Add(...);
foreach (Task t in taskList)
t.Start();
}
private void stlFile_OnFinished(object sender, EventArgs e)
{
runningTasks--;
if (runningTasks <= 0)
this.Invoke(new Action(() => button1.Enabled = true));
}

Related

Why ProgressBar does not displaying the current value / does not refreshing?

I use the following code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
progressBar1.Value = 0;
progressBar1.Step = 1;
progressBar1.Maximum = 100;
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(100);
progressBar1.PerformStep();
label1.Text = (i + 1).ToString();
this.Refresh();
}
}
}
But, even after this.Refresh(); the value of the progress bar does not updated. Only the label updated. When the labels already show 100, for progress bar stil have more few steps to finish.
What i do wrong?
why the value of the progress bar is not updated?
How i should do it correct?
are you using Task, async, await? this is a common sample in winforms
see IProgress
public void DoWork(IProgress<int> progress)
{
// This method is executed in the context of
// another thread
for (int j = 0; j < 100000; j++)
{
//DO something
// Use progress to notify UI thread that progress has
// changed
if (progress != null)
progress.Report((j + 1) * 100 / 100000);
}
}
private async void button_Click(object sender, EventArgs e)
{
progressBar.Maximum = 100;
progressBar.Step = 1;
var progress = new Progress<int>(v =>
{
// This lambda is executed in context of UI thread,
// so it can safely update form controls
progressBar.Value = v;
});
// Run operation in another thread
await Task.Run(() => DoWork(progress));
}
I tried your code and it worked fine for me, did you add any special properties to your progress bar?
Assuming that it is all there is to it, try removing it and adding a new one without adjusting its default properties, you can also try adjusting the value in your Thread.Sleep() so that you can see the progress more

Create and show progressBar with backgroundWorker - VS2013

I want show marquee progress bar in another thread of my app.
Here is my code:
bkgWorker->RunWorkerAsync();
private: System::Windows::Forms::ProgressBar^ progressBar;
private: System::Void bkgWorker_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
progressBar = (gcnew System::Windows::Forms::ProgressBar());
progressBar->Location = System::Drawing::Point(548, 349);
progressBar->MarqueeAnimationSpeed = 15;
progressBar->Name = L"progressBar";
progressBar->Size = System::Drawing::Size(100, 23);
progressBar->Style = System::Windows::Forms::ProgressBarStyle::Marquee;
progressBar->TabIndex = 23;
progressBar->Show();
}
private: System::Void bkgWorker_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e) {
progressBar->Hide();
}
There is no fault, but I do not see the progress bar on my form.
What am I doing wrong ?
Thanks for help.
there are better and newer solutions replaced the old good background worker.
I suggest you to look at async await design.
Read this post: Reporting Progress from Async Tasks
The code should look something like this:
public async void StartProcessingButton_Click(object sender, EventArgs e)
{
// The Progress<T> constructor captures our UI context,
// so the lambda will be run on the UI thread.
var progress = new Progress<int>(percent =>
{
textBox1.Text = percent + "%";
});
// DoProcessing is run on the thread pool.
await Task.Run(() => DoProcessing(progress));
textBox1.Text = "Done!";
}
public void DoProcessing(IProgress<int> progress)
{
for (int i = 0; i != 100; ++i)
{
Thread.Sleep(100); // CPU-bound work
if (progress != null)
progress.Report(i);
}
}

Adding items to a ListBox in a parallel way

I'm writing a simple application (for testing purposes) that adds 10 M elements to a ListBox. I'm using a BackgroundWorker to do the work and a ProgressBar control to display the progress.
Each element is a just a "Hello World!" string with and index that I'm adding during the process. My program takes ~ 7-8 seconds to fill the ListBox, and I thought if it's possible to speed up this, by using all the available cores on my PC (8).
To achieve that, I've tried to use the TPL library, more precise the Parallel.For loop, but the results are unpredictable or it doesn't work as I want it to.
Here's the code of my application:
private BackgroundWorker worker = new BackgroundWorker();
private Stopwatch sw = new Stopwatch();
private List<String> numbersList = new List<String>();
public MainWindow()
{
InitializeComponent();
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
sw.Start();
int max = 10000000;
int oldProgress = 0;
for (int i = 1; i <= max; i++)
{
numbersList.Add("Hello World! [" + i + "]");
int progressPercentage = Convert.ToInt32((double)i / max * 100);
// Only report progress when it changes
if (progressPercentage != oldProgress)
{
worker.ReportProgress(progressPercentage);
oldProgress = progressPercentage;
}
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pb.Value = e.ProgressPercentage;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lstLoremIpsum.ItemsSource = numbersList;
lblCompleted.Content = "OK";
lblCompleted.Content += " (" + numbersList.Count + " elements added" + ")";
lblElementiLista.Content += " (" +sw.Elapsed.TotalSeconds + ")";
worker.Dispose();
}
}
And the parallel implementation that I've tried to write (this goes in DoWork):
Parallel.For(1, max, i =>
{
lock (lockObject)
{
numbersList.Add("Hello World! [" + i + "]");
}
int progressPercentage = Convert.ToInt32((double)i / max * 100);
// Only report progress when it changes
if (progressPercentage != oldProgress)
{
worker.ReportProgress(progressPercentage);
oldProgress = progressPercentage;
}
});
The results is that the application freezes, and takes about 15 seconds to fill up my ListBox. (The elements are also unordered)
What can be done in this case and will parallelism speed up the "filling" process?
The lock statement in your thread basically reduces your parallel processing to sequential processing, but with the overhead of acquiring a lock (making it effectively slower).
Also there are a limited number of thread pool threads which can be used here so you won't get your full 10m concurrently adding.
I think a better way is to use a non UI thread to populate the list and then bind it afterwards - this will ensure the UI isn't frozen/unusable while the 10 million iteration loop is running:
public MainWindow()
{
InitializeComponent();
Task.Factory.StartNew(PopList);
}
Then you can call the UI thread when needed:
private void PopList()
{
sw.Start();
int max = 10000000;
int oldProgress = 0;
for (int i = 1; i <= max; i++)
{
numbersList.Add("Hello World! [" + i + "]");
int progressPercentage = Convert.ToInt32((double)i / max * 100);
// Only report progress when it changes
if (progressPercentage != oldProgress)
{
Dispatcher.BeginInvoke(new Action(() => { pb.Value = progressPercentage; }));
oldProgress = progressPercentage;
}
}
Dispatcher.BeginInvoke(new Action(() => { lstLoremIpsum.ItemsSource = numbersList; }));
}
In an MVVM world you can just set the bound IEnumerable instead of the ItemsSource as shown in the above example.
You are locking the list on each add, and all the process load is just that, adding an element to the list, so instead of speeding up things you are slowing them because there are really no parallel work.
If your list of items is of a known size (as it seems), instead of a list create an array with the appropiated size and then in the parallel for loop set the appropiated item to it's value, in this way no locking is performed and it should be faster.
Also, in your code you don't show when the list view is populated, just the list, so I suppose you are using this list as datasource, before setting it do a listView.BeginUpdate() and after setting it listView.EndUpdate(), it may speed up things a bit,m the listview is a bit slow when adding elements.
If you use Parallel.For, then you don't need a BackgroundWorker. And the Worker doesn't work anymore as expected anyway, since you're trying to access it from another thread.
Remove the BackgroundWorker and do the Parallel.For directly, using Interlocked methods to update the progress bar:
private int ProgressPercentage { get; set; }
private void DoWork()
{
Parallel.For(1, max, i =>
{
lock (lockObject)
{
numbersList.Add("Hello World! [" + i + "]");
}
int progressPercentage = Convert.ToInt32((double)i / max * 100);
// Only report progress when it changes
if (progressPercentage != oldProgress)
{
Interlocked.Exchange(ProgressPercentage, progressPercentage);
ShowProgress();
}
});
}
private void ShowProgress()
{
pb.Value = ProgressPercentage;
}

ReportProgress doesn't call progressChanged with tasks in c#

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int currentProgress=-1;
while (currentProgress<length)
{
currentProgress=Worker.progress;
backgroundWorker1.ReportProgress(currentProgress);
Thread.Sleep(500);
length = Worker.UrlList.Count;
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int ix = e.ProgressPercentage;
progressBar1.Value = ix;
lblText.Text =ix+" %";
}
I wrote a program to download page sources by reading a file have about 1000 URLs. so I used Tasks to download pages async. here Worker.progress is the currently executed URL amount. though the debuger hits the backgroundWorker1.ReportProgress(currentProgress); it never enter to the backgroundWorker1_ProgressChanged.
private void StartButton_Click(object sender, EventArgs e)
{
t.makeUrlList(inputFile);
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerAsync();
t.RunTasks();
Application.Exit();
}
background worker initializes when start button clicks...
here is where my tasks are created....
public void RunTasks()
{
if (numOfTasks > UrlList.Count)
numOfTasks=UrlList.Count-1;
Task[] t = new Task[numOfTasks];
int j = 0;
while ( j < UrlList.Count-1)
{
for (int i = 0; (i < t.Count())&&(j<UrlList.Count-1); i++)
{
try
{
if (t[i].IsCompleted || t[i].IsCanceled || t[i].IsFaulted)
{
t[i] = Task.Run(() => FindWIN(j));
j++;
progress = j;
}
}
catch (NullReferenceException ex)
{
t[i] = Task.Run(() => FindWIN(j));
j++;
progress = j;
}
}
}
}
If you want to BackgroundWorker supports updating progress information, the value of WorkerReportsProgress should be set to true . If this property is true , the user code can call ReportProgress for initiating event ProgressChanged .
Background worker initialization:-
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork+=backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged+=backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerAsync();
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int currentProgress = -1;
decimal length=1000;
while (currentProgress < length)
{
currentProgress = Worker.progress;
backgroundWorker1.ReportProgress(currentProgress);
Thread.Sleep(500);
length = Worker.UrlList.Count;
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
int ix = e.ProgressPercentage;
progressBar1.Value = ix;
lblText.Text = ix + " %";
}
See the demo code below. This is mostly untested, and certainly isn't 'production standard', but it should give you a good start!
It uses a ConcurrentQueue to hold the list of URLs to be processed. This is threadsafe, and makes life a lot easier.
It has a configurable number of urls and tasks. It's best not to make 1000 tasks, but instead have a queue of work items, and a smaller pool of Tasks which 'pull items' off the queue until it's empty. This means you can performance test different numbers of Tasks and find the best value for your problem.
It uses Invoke when updating the progress bar - this avoids the cross-thread exception.
No BackgroundWorker - just TaskFactory and Task
public partial class Form1 : Form
{
private const int UrlCount = 1000;
private const int taskCount = 10;
private ConcurrentQueue<string> urlList;
private List<Task> taskList;
public Form1()
{
InitializeComponent();
}
private void ResetQueue()
{
// fake up a number of strings to process
urlList = new ConcurrentQueue<string>(Enumerable.Range(0, UrlCount)
.Select(i => "http://www." + Guid.NewGuid().ToString() + ".com"));
}
private void button1_Click(object sender, EventArgs e)
{
ResetQueue();
var taskFactory = new TaskFactory();
// start a bunch of tasks
taskList = Enumerable.Range(0, taskCount).Select(i => taskFactory.StartNew(() => ProcessUrl()))
.ToList();
}
void ProcessUrl()
{
string current;
// keep grabbing items till the queue is empty
while (urlList.TryDequeue(out current))
{
// run your code
FindWIN(current);
// invoke here to avoid cross thread issues
Invoke((Action)(() => UpdateProgress()));
}
}
void FindWIN(string url)
{
// your code here
// as a demo, sleep a sort-of-random time between 0 and 100 ms
Thread.Sleep(Math.Abs(url.GetHashCode()) % 100);
}
void UpdateProgress()
{
// work out what percentage of the queue is processed
progressBar1.Value = (int)(100 - ((double)urlList.Count * 100.0 / UrlCount));
}
}
You should set WorkerReportsProgress property of your worker to true on initialization stage.

C# wpf dispatcher thread

I am trying to create a new Thread and put it to sleep in some occasions, but when I do it the main thread sleep, not only the one that I had created. I am using a Dispatcher.BeginInvoke but this is only to "give a permission" from the main thread to access to the method.
It works because it does not give me an InvalidOperationException, but the "focus" of the created thread losses when the linked method start.
I think I should use a ManualResetEvent to wait for the created Thread, but I do not know how doing it. I have been looking for possible solutions but no one works.
I think this should be easy but i cannot do it. The following code is Below:
void EmpujeDispatcher(object objeto)
{
this.Dispatcher.BeginInvoke(new Action<object>(Empuje), objeto);
}
private void Empuje(object objeto)
{
Thread.Sleep(2000); MessageBox.Show("This should not freeze the window");
Canvas Bacteria = objeto;
double PosX = Canvas.GetLeft(Bacteria);//PosiciĆ³n del sender
double PosY = Canvas.GetTop(Bacteria);//Lo mismo
Bacterias BacteriaInstancia = InstanciaBacterias[Bacteria.Uid];//Se busca la bacteria para relacionarla con al instancia
BacteriaInstancia.posX = PosX;
BacteriaInstancia.posY = PosY;
// BacteriaInstancia.Moverse();
if (BacteriaInstancia.momemtum <= 0)
{
Canvas.SetTop(Bacteria, PosY); Canvas.SetLeft(Bacteria, PosX);//Para el empuje
dispatcherTimer.Stop();
}
else
{ //Rebote:
BacteriaInstancia.Posicion();
PosX = BacteriaInstancia.posX;
PosY = BacteriaInstancia.posY;
if (PosX + Bacteria.Width >= CanvasSimulador.Width) { BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 1; }
if (PosX <= 0) { BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 3; }
if (PosY + Bacteria.Height >= CanvasSimulador.Height) { PosY = CanvasSimulador.Height - Bacteria.Height; BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 2; }
if (PosY <= 0) { PosY = 1; BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 4; }
Canvas.SetTop(Bacteria, PosY); Canvas.SetLeft(Bacteria, PosX);
BacteriaInstancia.momemtum = Math.Sqrt(Math.Pow(BacteriaInstancia.Vfx, 2) + Math.Pow(BacteriaInstancia.Vfy, 2));
ControlFlujo = BacteriaInstancia.momemtum;
}
private void EmpujeEvent(object sender, MouseButtonEventArgs e)
{
Thread TimerClockThread = new Thread(new ParameterizedThreadStart(EmpujeDispatcher));
TimerClockThread.IsBackground = true;
TimerClockThread.Start(sender);
}
This is not exacly the code because in this one Dispatcher does not have any sense, if I create the Thread without dispatcher
TimerClockThread = new Thread( new ParameterizedThreadStart(Empuje));
It works well... because it's a MessageBox, but in the original I have a lot of code inside of the "Empuje".
Thanks for your attention and hopefully you can help me :)
Your Dispatcher.Invoke forces your Empuje method to be called on the UI thread. If you want to update the screen, you should move the call to the background thread:
TimerClockThread = new Thread( new ParameterizedThreadStart(Empuje));
private void Empuje(object objeto)
{
Thread.Sleep(2000);
Dispatcher.BeginInvoke(new Action(() => {
MessageBox.Show("This should not freeze the window");
}));
//........ Do stuff.....
}
In modern C# with async however, you can remove all code and instead write:
private async void EmpujeEvent(object sender, MouseButtonEventArgs e)
{
await Task.Delay(2000);
MessageBox.Show(...);
}
Your function EmpujeDispatcher is using the same dispatcher that your GUI thread is associated with. That means you are telling the dispatcher to execute Empuje asynchronously, unfortunately it is executed on the GUI thread. At least that's what I think.
A BackgroundWorker is quite fit for this task. The shortest piece of code to implement it looks like this:
var worker = new BackgroundWorker();
worker.DoWork += (s,e) =>
{
Thread.Sleep(2000);
// Do Stuff...
};
worker.RunWorkerAsync();
Searching SO will yield a plethora of Q&A about the BackgroundWorker (i.e. this or this)

Categories

Resources