Je veux que mon programme attende après la ligne ci-dessous
frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false);
comme ci-dessus, la méthode appelle en interne le thread via la méthode StartProcessWithProgress (). Je veux que ce thread soit terminé avant que // la logique de code -2 ne soit exécutée. Dans le même temps, il ne doit pas arrêter la mise à jour de l'interface utilisateur effectuée par frmProgressBar.UpdateProgress (). Comment puis-je faire cela?
namespace NS1
{
public partial class frmMain : Form
{
private void button1_Click(object sender, EventArgs e)
{
frmProgressBar frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false);
//code logic - 2
MessageBox.Show("This is executing immediately.
I want to wait until above thread is complete");
}
}
public partial class frmProgressBar : Form
{
public void UpdateProgress(String strTextToDisplayOnProgress)
{
progressBar1.BeginInvoke(
new Action(() =>
{
progressBar1.Value++;
lblFileName.Text = strTextToDisplayOnProgress;
if (progressBar1.Value == progressBar1.Maximum)
{
this.Hide();
}
}));
}
public delegate void DelProgress();
public void StartProcessWithProgress(DelProgress delMethodCode, int maxCount)
{
InitializeProgress(maxCount);
Thread backgroundThread = new Thread(new ThreadStart(delMethodCode));
backgroundThread.Start();
}
}
public static class PullMSI
{
public static frmProgressBar ExtractByMSIName(String strProductFilePath, bool reNameMSI)
{
frmProgressBar frmProgressBar = new frmProgressBar();
frmProgressBar.StartProcessWithProgress(() =>
{
//StreamRader sr declaration and other code
while (!sr.EndOfStream)
{
//logic here
frmProgressBar.UpdateProgress("Copying sr.msiname");
}
}, 2);
return frmProgressBar;
}
}
}
Je suis très surpris que vous n'ayez jamais travaillé avec aucun d'entre eux auparavant, mais je recommanderais vraiment de lire sur le filetage en C # car il est fondamentalement important de comprendre les subtilités et d'apprendre le langage.
Voici trois façons différentes de réaliser ce que vous voulez:
1. Utilisation des événements de réinitialisation (lecture supplémentaire: https://msdn.Microsoft.com/en-us/library/system.threading.manualreseteventslim (v = vs.110) .aspx ). Si votre version C # n'a pas le ManualResetEventSlim
, remplacez-le par ManualResetEvent
et changez Wait()
par WaitOne()
class LockingWithResetEvents
{
private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);
public void Test()
{
MethodUsingResetEvents();
}
private void MethodUsingResetEvents()
{
ThreadPool.QueueUserWorkItem(_ => DoSomethingLong());
ThreadPool.QueueUserWorkItem(_ => ShowMessageBox());
}
private void DoSomethingLong()
{
Console.WriteLine("Doing somthing.");
Thread.Sleep(1000);
_resetEvent.Set();
}
private void ShowMessageBox()
{
_resetEvent.WaitOne();
Console.WriteLine("Hello world.");
}
}
2) Utilisation de la bibliothèque parallèle de tâches (TPL). Pour en savoir plus: https://msdn.Microsoft.com/en-us/library /dd460717(v=vs.110).aspx
class LockingWithTPL
{
public void Test()
{
Task.Factory.StartNew(DoSomethingLong).ContinueWith(result => ShowMessageBox());
}
private void DoSomethingLong()
{
Console.WriteLine("Doing somthing.");
Thread.Sleep(1000);
}
private void ShowMessageBox()
{
Console.WriteLine("Hello world.");
}
}
3) Utilisation d'Async/Await. Pour en savoir plus: https://msdn.Microsoft.com/en-us/library/hh191443.aspx
class LockingWithAwait
{
public void Test()
{
DoSomething();
}
private async void DoSomething()
{
await Task.Run(() => DoSomethingLong());
ShowMessageBox();
}
private async void DoSomethingLong()
{
Console.WriteLine("Doing somthing.");
Thread.Sleep(10000);
}
private void ShowMessageBox()
{
Console.WriteLine("Hello world.");
}
}
Aussi bon à savoir: Mutex ( https://msdn.Microsoft.com/en-us/library/system.threading.mutex (v = vs.110) .aspx ), Semaphore (- https://msdn.Microsoft.com/en-us/library/system.threading.semaphore (v = vs.110) .aspx ), Lock ( https://msdn.Microsoft .com/en-us/library/c5kehkcz.aspx ), SemaphoreSlim ( https://msdn.Microsoft.com/en-us/library/system.threading.semaphoreslim (v = vs.110 ) .aspx ), Monitor ( https://msdn.Microsoft.com/en-us/library/system.threading.monitor (v = vs.110) .aspx ) et Interlocked ( https://msdn.Microsoft.com/en-us/library/system.threading.interlocked (v = vs.110) .aspx ).
Si vous utilisez .NET 4.0 (avec VS2012) ou supérieur, vous pouvez le faire assez facilement avec Task Parallel Library
et async-await
:
private async void button1_Click(object sender, EventArgs e)
{
frmProgressBar frmProgressBarObj = await Task.Run(() =>
PullMSI.ExtractByMSIName("products.txt", false));
MessageBox.Show(string.Format("Returned {0}", frmProgressBarObj.ToString());
}
Pour .NET 4, vous devrez ajouter Microsoft.Bcl.Async
.