Ahoj,
v rámci semestrální práce mám porovnat metody pro asynchronní vykonávání operací v C#. Mohl by mi někdo ze šikovných C#ářů povědět, co mám v kódu blbě, že mi BackgroundWorker blokuje uživatelské rozhraní?
Udělal jsem si třídu pro zabalelní práce pomocí různých technik...
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
namespace PdaSemPrace
{
class AsynchronniOperace
{
private static BackgroundWorker _worker;
private static Stopwatch _hodiny;
private static long _pocetOpakovani;
private static ProgressBar _progressBar;
/// <summary>
/// Parametrický konstruktor, který zaregistruje BackgroundWorker a ProgressBar.
/// V konstruktoru se nastaví Worker, který se poté v prezenční vrstvě spustí
/// přes RunWorkerAsync() a zruší přes CancelAsync();
/// </summary>
/// <param name="pB">ProgressBar z Windows Form, jehož se týká operace.</param>
/// <param name="pocetOpakovani">Kolikrát se má projet cyklus při načtení ProgressBaru.</param>
public AsynchronniOperace(ProgressBar pB, long pocetOpakovani)
{
// Singleton
if (_worker != null || _progressBar != null || _hodiny != null)
{
return;
}
_hodiny = new Stopwatch();
_pocetOpakovani = pocetOpakovani;
_progressBar = pB;
_worker = new BackgroundWorker
{
WorkerSupportsCancellation = true,
WorkerReportsProgress = true
};
_worker.DoWork += bw_DoWork;
_worker.ProgressChanged += bw_ProgressChanged;
_worker.RunWorkerCompleted += bw_RunWorkerCompleted;
}
/// <summary>
/// Metoda spustí pomocí Invoke načtení ProgressBaru.
/// Metodu spouštět ve vlákně (Thread) vytvořeném v prezenční vrstvě.
/// </summary>
public static void VeVlakneNacistProgressBarInvoke()
{
_hodiny.Start();
for (var i = 0; i < _pocetOpakovani; i++)
{
_progressBar.Invoke(new Action(() => _progressBar.Value = (int)(((double)i/_pocetOpakovani) * 100)));
}
_progressBar.Invoke(new Action(() => _progressBar.Value = 100));
_hodiny.Stop();
MessageBox.Show(
@"Akce pomocí Invoke při " + _pocetOpakovani + @" opakováních trvala " + _hodiny.ElapsedMilliseconds +
@" ms.", @"Výsledek testu");
_hodiny.Reset();
}
/// <summary>
/// Metoda spustí pomocí BeginInvoke načtení ProgressBaru.
/// Metodu spouštět ve vlákně (Thread) vytvořeném v prezenční vrstvě.
/// </summary>
public static void VeVlakneNacistProgressBarBeginInvoke()
{
_hodiny.Start();
for (var i = 0; i < _pocetOpakovani; i++)
{
_progressBar.BeginInvoke(new Action(() => _progressBar.Value = (int)(((double)i / _pocetOpakovani) * 100)));
}
_progressBar.BeginInvoke(new Action(() => _progressBar.Value = 100));
_hodiny.Stop();
MessageBox.Show(
@"Akce pomocí BeginInvoke při " + _pocetOpakovani + @" opakováních trvala " +
_hodiny.ElapsedMilliseconds + @" ms.", @"Výsledek testu");
_hodiny.Reset();
}
/// <summary>
/// Event, který se přiřadí do Worker.DoWork.
/// </summary>
private static void bw_DoWork(object sender, CancelEventArgs e)
{
var bw = sender as BackgroundWorker;
_hodiny.Start();
for (var i = 0; i < _pocetOpakovani; i++)
{
if (bw != null && bw.CancellationPending)
{
e.Cancel = true;
_progressBar.Value = 0;
return;
}
if (bw != null){bw.ReportProgress((int) (((double) i/_pocetOpakovani)*100));}
}
if (bw != null){bw.ReportProgress(100);}
}
/// <summary>
/// Event, který se přiřadí do Worker.ProgressChanged.
/// </summary>
private static void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
_progressBar.Value = e.ProgressPercentage;
}
/// <summary>
/// Event, který se přiřadí do Worker.RunWorkerCompleted.
/// </summary>
private static void bw_RunWorkerCompleted(object sender, AsyncCompletedEventArgs e)
{
_hodiny.Stop();
if (e.Cancelled)
{
MessageBox.Show(@"Akce byla zrušena.", @"Výsledek operace");
}
else if (e.Error != null)
{
MessageBox.Show(@"Během vykonávání akce došlo k chybě.", @"Výsledek operace");
}
else
{
MessageBox.Show(
@"Akce pomocí BackgroundWorkeru při " + _pocetOpakovani + @" opakováních trvala " +
_hodiny.ElapsedMilliseconds + @" ms.", @"Výsledek testu");
}
_hodiny.Reset();
}
/// <summary>
/// Veřejná metoda pro spuštění BackgroundWorkeru.
/// </summary>
public static void RunWorkerAsync()
{
if (!_worker.IsBusy)
{
_worker.RunWorkerAsync();
}
}
/// <summary>
/// Veřejná metoda pro zabití BackGroundWorkeru.
/// </summary>
public static void CancelAsync()
{
if (_worker.WorkerSupportsCancellation)
{
_worker.CancelAsync();
}
}
}
}
Ve formuláři poté inicializuji třídu přes
var operace = new AsynchronniOperace(progressBar1, 10000000);
progressBar1 je ProgressBar na mém formuláři. Akce normálně proběhne, ale blokuje mi UI (nemůžu akci zrušit), netuším proč.
Děkuji za nápady.