I'm working on a downloader manger to my app but I couldn't know how to make the Stop button work I search for solution but I couldn't find anything can help me
The code is
[c#]
private void btnDownload_Click(object sender, EventArgs e)
{
btnDownload.Enabled = false;
btnStop.Enabled = true;
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri(url.Text), path.Text ; )
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Download completed!");
}
private void btnstop (object sender , e)
{
btnDownload.Enabled = true;
btnstop.Enabled = false;
progressbar.value = 0;
}
As Nitro.de says, you should use WebClient.CancelAsync.
Cancels a pending asynchronous operation.
and remember checking if the e.Cancelled is true
private void Completed(object sender, AsyncCompletedEventArgs e)
{
if(e.Cancelled)
MessageBox.Show("Download cancelled!");
else
MessageBox.Show("Download completed!");
}
To cancel a WebClient async request, you can call the WebClient.CancelAsync method as found here. Note that this still calls the download completed handler, so you will have to check if e.Canceled is true in your Completed function before showing the message box.
Related
I'm doing a simple login form that will show the login process after they click button. It will verify the user access rights and give true or false.
I got an error on this.Hide();
System.InvalidOperationException: 'Cross-thread operation not valid: Control 'formLogin' accessed from a thread other than the thread it was created on.'
Any help would be greatly appreciated. Thanks!!
private void btnLogin_Click(object sender, EventArgs e)
{
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
PBLogin.Style = ProgressBarStyle.Marquee;
PBLogin.MarqueeAnimationSpeed = 50;
bgw.RunWorkerAsync();
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
PBLogin.Style = ProgressBarStyle.Blocks;
PBLogin.MarqueeAnimationSpeed = 0;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
if (CheckAuthorization())
{
MessageBox.Show("Login Successfully");
TestScript next = new TestScript();
next.Show();
this.Hide();
}
else
{
MessageBox.Show("Login Failed");
}
From a background thread you can't reach the UI, that's what the exception is trying to tell you. In your background thread you should try to focus only on the Authorization logic itself. Try to avoid UI component manipulation.
In the RunWorkerCompleted event you can indeed modify the UI components. So, do the calculation on a dedicated background thread and do the UI manipulation inside the completion event.
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//TODO: Check against e.Error and e.Cancelled before you try to access e.Result
if((bool)e.Result)
{
//UI modification
}
else
{
//UI modification
}
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
var isAuthorized = CheckAuthorization();
e.Result = isAuthorized;
}
I've implemented a background worker onLoad of my window. The code in the Progress_Load is reached but after that the DoWork function is not called. The function excel.Read() reads a quite big excel tabel into a list, this takes about 1.5 min and that's why i want to do it a-syn.
public List<Part> partList = new List<Part>() { };
//boolean that will be set when the backgroundworker is done
public bool listRead = false;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
_Excel excel = new _Excel();
partList = excel.Read();
backgroundWorker1.ReportProgress(100);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Message m;
if (e.Cancelled == true)
{
m = new Message("The operation has been canceld!", "Canceled");
this.Close();
}
else if (e.Error != null)
{
Error er = new Error("Error: " + e.Error.Message, "Error!");
this.Close();
}
else
{
listRead = true;
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
//Set the text.
this.Text = e.ProgressPercentage.ToString();
}
private void Progress_Load(object sender, EventArgs e)
{
if (backgroundWorker1 == null)
{
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.RunWorkerAsync();
}
Probably it's not null when loading the form. You may have added the BackgroundWorker via the designer. If so it's never null, you can hook up the event handlers also from its Properties/Events.
Try this
private void Progress_Load(object sender, EventArgs e)
{
if (backgroundWorker1 == null)
{
backgroundWorker1 = new BackgroundWorker();
}
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.RunWorkerAsync();
}
In WPF Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction); is a another option because report progress is not much useful in your scenario. Here example for Dispatcher and Background worker comparison.
Unfortunately I was not able to find relevant answer to my problem. I have a object encoder that has an event "VideoEncoding". It passes custom EncodingEventArgs that include various Properties like Progress, Size etc. I can output this info to Console or write to text file. But when I try to utilize it in WinForms I'm not able to pass that information to UI like label or progress bar. I tried different approaches. Background Worker seems like a good idea, The problem is that Background Worker cannot subscribe to VideoEncoding event, neither it will take my custom EventArgs. This is what i was able to put together. Maybe there is a different way to do it using delegates that would communicate with UI. Any suggestions are welcome. Thank you.
public partial class Form1 : Form
{
private BackgroundWorker bw;
int _progress;
public Form1()
{
InitializeComponent();
this.bw = new BackgroundWorker();
this.bw.DoWork += new DoWorkEventHandler(bw_DoWork);
this.bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
this.bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
this.bw.WorkerReportsProgress = true;
this.button1.Click += new EventHandler(button1_Click);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.label1.Text = "The job is: " + e.Result.ToString();
this.button1.Enabled = true;
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.label2.Text = e.ProgressPercentage.ToString() + "% complete";
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
this.Encode
worker.ReportProgress(_progress);
e.Result = "Completed";
}
private void button1_Click(object sender, EventArgs e)
{
if (!this.bw.IsBusy)
{
this.bw.RunWorkerAsync();
this.button1.Enabled = false;
}
}
public void Encode()
{
var job = new EncodingJob();
//setup encoding job
//subscribe to an event
ffmpeg.VideoEncoding += GetProgress;
ffmpeg.DoWork(job);
}
public void GetProgress(object sender, EncodingEventArgs e)
{
_progress = (int)e.Progress;
}
}
Try to call the background workers ReportProgress in the GetProgress Method. How should the form know your progress if you don't signalize it?
I have another question :(.
I'm trying to download multiple files for my application.
My question is: What do I have to do to check if the first download is done and then continue to the second download and so on?
This is my code atm:
private void DownloadBukkit()
{
MySingleton.Instance.FirstStartProgress = "Downloading Bukkit.jar... Please stand by...";
webClient.DownloadFileAsync(new Uri(MySingleton.Instance.BukkitDownloadLink), Jar_Location);
webClient.DownloadProgressChanged += backgroundWorker1_ProgressChanged;
webClient.DownloadFileCompleted += (webClient_DownloadFileCompleted);
}
private void DownloadDll()
{
if (!webClient.IsBusy)
{
MySingleton.Instance.FirstStartProgress = "Downloading HtmlAgilityPack.dll... Please stand by...";
webClient2.DownloadFileAsync(new Uri(Dll_HtmlAgilityPackUrl), Dll_HtmlAgilityPackLocation);
webClient2.DownloadProgressChanged += backgroundWorker1_ProgressChanged;
webClient2.DownloadFileCompleted += (webClient2_DownloadFileCompleted);
}
}
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
DownloadDll();
}
void webClient2_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
Invoke((MethodInvoker)
Close);
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Invoke((MethodInvoker)
delegate
{
labelProgress.Text = MySingleton.Instance.FirstStartProgress;
progressBar1.Value = e.ProgressPercentage;
});
}
I have checked this link: DownloadFileAsync multiple files using webclient but I didn't really understand how to implant this :(. (I'm quite new to C#)
The DownloadFileCompleted event is your signal to know that you are finished downloading the file.
From MSDN:
This event is raised each time an asynchronous file download operation
completes.
It's not clear from your code, where and how webClient and webClient2 are declared but essentially, you can start your second download when the first DownloadFileCompleted event is fired. Note, however, that you can perform the download of 2 different files concurrently provided you use 2 separate instances of WebClient.
Here is the fast forward code you can change it as per your requirement .
WebClient client = null;
public FileDownloader()
{
InitializeComponent();
client = new WebClient();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFileCompleted += client_DownloadFileCompleted;
}
void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
lblMessage.Text = "File Download Compeleted.";
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
lblMessage.Text = e.ProgressPercentage + " % Downloaded.";
}
private void StartDownload(object sender, RoutedEventArgs e)
{
if (client == null)
client = new WebClient();
//Loop thru your files for eg. file1.dll, file2.dll .......etc.
for (int index = 0; index < 10; index++)
{
//loop on files
client.DownloadFileAsync(
new Uri(
#"http://mywebsite.com/Files/File" + index.ToString() + ".dll"
, UriKind.RelativeOrAbsolute),
#"C:\Temp\file+" + index.ToString() + ".dll");
}
}
in my Winform a read file method is implemented on button click.when big files are read my Ui hangs until the loop is over.I need to have control on my UI all the time.
i know that is done before and i tried some but i am still having an
error when i try to use some form controls like this :(translated!)
the access of control element comboBox1 is from another thread rather than the thread in which it is created in !!!
private void button1_Click(object sender, EventArgs e)
{
//some code
using (StreamReader sr = new StreamReader(file, System.Text.Encoding.ASCII))
{
while (sr.EndOfStream == false)
{
line = sr.ReadLine();
UpdateProgressBar(line.Length);
}
}
//some code
}
Add a BackgroundWorker to your class on Form (or Control) load. Then hookup its events:
BackgroundWorker _worker;
void Form_Load(object sender, EventArgs e)
{
_worker = new BackgroundWorker();
_worker.DoWork += _worker_DoWork;
_worker.RunWorkerCompleted += _worker_RunWorkerCompleted;
_worker.ProgressChanged +=_worker_ProgressChanged;
_worker.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
_worker.RunWorkerAsync(file);//pass on the file name
}
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
var file = e.Argument as String;
using (StreamReader sr = new StreamReader(file, Encoding.ASCII))
{
while (sr.EndOfStream == false)
{
line = sr.ReadLine();
_worker.ReportProgress(line.Length);
}
}
}
private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//Report porogress bar change
UpdateProgressBar(e.ProgressPercentage);
}
private void _worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
//do any stuff you want after reading the file.
}
Read more about this here.
Use a BackgroundWorker to do the work on a separate thread.
Use BackgroundWorker
[edit] Tutorial available here
You really should have consulted the documentation before asking a question. Anyways, here's an example of how you can do it using a BackgroundWorker:
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker;
worker.WorkerReportsProgress = true;
worker.ProgressChanged += ProgressChanged;
worker.DoWork += ReadStream;
worker.RunWorkerAsync(comboBox1.Text);
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UpdateProgressBar(e.ProgressPercentage);
comboBox1.Text = e.UserState.ToString();
}
private void ReadStream(object sender, DoWorkEventArgs doWorkEventArgs)
{
BackgroundWorker worker = sender as BackgroundWorker;
string line;
string comboBoxText = doWorkEventArgs.Argument.ToString();
using (StreamReader sr = new StreamReader("file", System.Text.Encoding.ASCII))
{
while (!sr.EndOfStream)
{
line = sr.ReadLine();
worker.ReportProgress(line.Length);
worker.ReportProgress(line.Length, "NEW COMBOBOX TEXT");
}
}
}
use backgroundworker to carry out heavy operations.
it has event to report progress of the task , so you can use it to update progress bar.