I have a background worker (as seen below) with DownloadFileCompleted/DownloadProgressChanged events. After several hours of testing and a lot of research, I couldn't get it to work. The file downloads successfully but the events don't run. I looked at a lot of documentation pages and searched for this issue here, but they don't seem to match my case... Would appreciate if someone could help me out on this one!
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler (webClient_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler (webClient_DownloadFileCompleted);
client.DownloadFileAsync(new Uri(myUri), path);
}
}
void webClient_DownloadFileCompleted(object s, AsyncCompletedEventArgs e)
{
Debug.WriteLine("Download completed!");
}
void webClient_DownloadProgressChanged(object s, DownloadProgressChangedEventArgs e)
{
Debug.WriteLine(e.BytesReceived);
}
There must be something else wrong with your code as running effectively that same code, it works fine.
Are you sure your program is simply not finished and closing before the work is done as a BackgroundWorker won't keep your application alive.
Here is my example, with a foreground Thread to keep the application alive until done
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
new Thread(() =>
{
var client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
client.DownloadFileAsync(new Uri("https://speed.hetzner.de/100MB.bin"), #"C:\Users\Luke\Desktop\100mb.bin");
}).Start();
}
private static void webClient_DownloadFileCompleted(object s, AsyncCompletedEventArgs e)
{
Debug.WriteLine("Download completed!");
}
private static void webClient_DownloadProgressChanged(object s, DownloadProgressChangedEventArgs e)
{
Debug.WriteLine(e.BytesReceived);
}
}
}
Related
I need some help with BackgroundWorker. Using Visual Studio 2015 and its windows forms
I'm new to this kind of things and really have no idea how it works etc. The code i have so far is based on various posts on here.
worker_DoWork_ not being fired at all but no idea why. I believe this is something to do with DataRceivedEventHandler because when I move the If i move the worker.DoWork += worker_DoWork_; and worker.RunWorkerAsync(); into button clicked event and disable DataReceivedEventHandler, method worker_DoWork_ is fired and I can update textBox with any static text assigned under DoSomeWork.
Also, I have no idea how to pass outline data into the text box via DoSomeWork.
Can someone help out please.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
namespace CMD_testing
{
public partial class Form1 : Form
{
BackgroundWorker worker;
private delegate void DELEGATE();
public Form1()
{
InitializeComponent();
worker = new BackgroundWorker();
}
private void button2_Click(object sender, EventArgs e)
{
Process process;
process = new Process();
process.StartInfo.FileName = #"C:\\Project\Test\Data.bat";
process.StartInfo.UseShellExecute = false;
// process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.BeginOutputReadLine();
// process.WaitForExit();
// process.Close();
}
private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
Console.WriteLine("Im here...");
worker.DoWork += worker_DoWork_;
//worker.RunWorkerAsync();
Console.WriteLine("Im here NOW");
Console.WriteLine(outLine.Data); //its outputed fine into the console
}
}
private void worker_DoWork_(object sender, DoWorkEventArgs e)
{
Console.WriteLine("I'm at worker_DoWork_");
Delegate del = new DELEGATE(DoSomeWork);
this.Invoke(del);
}
private void DoSomeWork()
{
Thread.Sleep(1000);
textBox1.Text = "????"; // how to pass outline.Data in here
}
}
}
The problem is that you outline RunWorkerAsync();. This methods fires the DoWork-Event which handle your asynchronous code. Via the EventArgs of DoWork you can reuse your results back to your mainthread and print it to your textbox. You can get the result in the RunWorkerCompleted-Event. Here a small example based on your code:
public partial class Form1 : Form
{
BackgroundWorker worker;
public Form1()
{
InitializeComponent();
worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_Completed;
}
private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
if (!worker.IsBusy) //Check if Worker is working and avoid exception
worker.RunWorkerAsync();
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
//Process some Long-Running Task
Thread.Sleep(5000)
e.Result = "Done!";
}
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e)
{
textbox.Text = e.Result.ToString();
}
}
}
Further you are maybe interested in Task Library which make the handling of threads easier.
UPDATE:
You say:
I want to update my Textbox in realtime.
This will print the text which your batchfile sends to Standardoutput directly in your textbox. So I don't think you need anymore.
private void OutputHandler(object sendingProcess, DataReceivedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.Data))
BeginInvoke(new MethodInvoker(() => { textBox1.Text = e.Data; }));
}
Thanks to #Sebi I have managed to get all issues sorted. It turns out I do not need a BackgroundWorker as some people suggested.
See the final code which works like a charm:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
namespace CMD_testing
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
Process process;
process = new Process();
process.StartInfo.FileName = #"C:\\Project\Test\Other Data.bat";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.BeginOutputReadLine();
process.Close();
}
private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
BeginInvoke(new MethodInvoker(() => { textBox1.AppendText(outLine.Data + Environment.NewLine); }));
}
}
}
}
I have a background worker used for running a time consuming sync operation with server and is working perfectly and UI is responsive during the operation
BackgroundWorker syncWorker = new BackgroundWorker();
syncWorker.WorkerReportsProgress = true;
syncWorker.DoWork += new DoWorkEventHandler(syncWorker_DoWork);
syncWorker.ProgressChanged += new ProgressChangedEventHandler(syncWorker_ProgressChanged);
syncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(syncWorker_RunWorkerCompleted);
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (xxxx item in actives)
{
target.ReportProgress(progress);
//time taking event running fine here..
}
target.ReportProgress(90);
}
private void syncWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lbl_progress.Text="Wait......";
}
private void syncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lbl_progress.Text="DONE!..";
}
Now i have to do a file download operation and i am using Webclient to do it using the code
WebClient downloadClient = new WebClient();
downloadClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(downloadClient_DownloadProgressChanged);
downloadClient.DownloadFileCompleted += new AsyncCompletedEventHandler(downloadClient_DownloadFileCompleted);
downloadClient.DownloadFileAsync(new Uri(fileUrl), download_path);
void downloadClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
int progress_value = int.Parse(Math.Truncate(percentage).ToString());
progress_value = (progress_value < 5) ? 5 : (progress_value > 95) ? 95 : progress_value;
lblDownloadProgress.Content = string.Format("DOWNLOADING - {0}%", progress_value.ToString());
}
void downloadClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
string item = (string)e.UserState;
if (e.Error != null )
{
lblDownloadProgress.Content = "Unable to download.Try again.....";
lblDownloadProgress.Foreground = Brushes.Red;
}
else if (e.Cancelled)
{
//Do Nothing
}
else
{
lblDownloadProgress.Content ="DOWNLOADED..";
}
}
Now can i run these 2 things parallely ? Like run background worker while downlaoding the file??
if file downloading finished first wait till the completion of background worker
if background worker finished first wait till completion of download
Enable controls after both operations finished and keep UI responsive during the whole time
You can run 2 Background worker in parallel but if you need check the state of one of them you can check if the backgroundworker is busy(doing work or completed).
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
while( downloadClient.IsBusy)
{
Sleep(5000);
//waiting downloadClient worker to complete
}
//continue the work
}
look into this for check some trick you can do.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading;
namespace download_demo
{
class Program
{
static void Main(string[] args)
{
BackgroundWorker MyWorker = new BackgroundWorker();
MyWorker.DoWork += MyWorker_DoWork;
MyWorker.RunWorkerCompleted +=MyWorker_RunWorkerCompleted;
MyWorker.RunWorkerAsync();
Console.ReadKey();
}
private static void MyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("both job completed");
}
private static void MyWorker_DoWork(object sender, DoWorkEventArgs e)
{
Thread download = new Thread(DownloadJob);
download.Start();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(20);
Console.WriteLine("doing some job while downloading ");
}
Console.WriteLine("waiting the end of download......... ");
download.Join();
}
private static void DownloadJob(object path)
{
/// process download the path
///simulate 20 seconde of download
for(int i = 0;i<100;i++)
{
Thread.Sleep(50);
Console.WriteLine("downloaded :" + i + " Ko");
}
}
}
}
I'm running a windows form with a background worker to update a textbox based on the output of a python script. Its all working pretty well, except the redirected output is not in real time; its delayed pretty significantly.
Any ideas how I can increase the redirected outputs response time?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.IO;
namespace JiraHeartBeat
{
public partial class Form1 : Form
{
delegate void AppendTextDelegate(string text);
BackgroundWorker Worker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
Worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
}
void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
StartButton.PerformClick();
}
private void StartButton_Click(object sender, EventArgs e)
{
if (!Worker.IsBusy)
{
Worker.RunWorkerAsync();
}
}
public void Worker_DoWork(object sender, DoWorkEventArgs e)
{
Process pro = new Process();
pro.StartInfo.RedirectStandardOutput = true;
pro.StartInfo.RedirectStandardError = true;
pro.StartInfo.UseShellExecute = false;
pro.StartInfo.CreateNoWindow = true;
pro.EnableRaisingEvents = true;
pro.OutputDataReceived += new DataReceivedEventHandler(OnDataReceived);
pro.ErrorDataReceived += new DataReceivedEventHandler(OnDataReceived);
pro.StartInfo.FileName = "C:\\Python27\\python.exe";
pro.StartInfo.Arguments = "\"C:\\Python27\\myscript.py\"";
try
{
pro.Start();
pro.BeginOutputReadLine();
pro.BeginErrorReadLine();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Thread.Sleep(5000 * 60);
}
public void OnDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
string temp = (e.Data) + Environment.NewLine;
appendText(temp);
}
}
public void appendText(string text)
{
if (ResultTextBox.InvokeRequired)
{
ResultTextBox.Invoke(new AppendTextDelegate(appendText), new object[] { text });
}
else
{
ResultTextBox.AppendText(text);
}
}
}
}
Actually, the issue is that Python does not redirect output until the script is complete. I believe IronPython will redirect while the script is running (have not tested this though), but unfortunately, regular Python must wait for the script to end before redirecting output.
Try removing the below line from the Worker_DoWork, I suspect it is delaying the execution of the RunWorkerCompleted event.
Thread.Sleep(5000 * 60);
EDIT
Since the above approach was attempted and did not solve the problem entirely I investigated a bit further and confirmed that when capturing the output from a python script the response is delayed. However, by adding a call to sys.stdout.flush() I was able to get the desired behavior. Here is the python script I used which worked successfully in my test.
import time
import sys
for x in xrange(0,11):
print x
time.sleep(1)
sys.stdout.flush()
I'll try to download file using this code.But file size is 0 KB.What is the correct and efficiency way to download the file.
private void DownloadFile()
{
using (WebClient Client = new WebClient())
{
Client.DownloadFileAsync(
new Uri("http://localhost/sn/userSelect.Designer.cs", UriKind.Absolute),
#"C:\xampp\htdocs\sn\test1.txt");
Client.Dispose();
}
}
Any one can give me the method for download the file over windows form program in C#.thanks
class Program
{
private static WebClient wc = new WebClient();
private static ManualResetEvent handle = new ManualResetEvent(true);
private static void Main(string[] args)
{
wc.DownloadProgressChanged += WcOnDownloadProgressChanged;
wc.DownloadFileCompleted += WcOnDownloadFileCompleted;
wc.DownloadFileAsync(new Uri(#"http://www.nattyware.com/bin/pixie.exe"), #"C:\\pixie.exe");
handle.WaitOne(); // wait for the async event to complete
}
private static void WcOnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (!e.Cancelled && e.Error == null)
{
//async download completed successfully
}
handle.Set(); // in both the case let the void main() know that async event had finished so that i can quit
}
private static void WcOnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// handle the progres in case of async
//e.ProgressPercentage
}
I am using VSTS 2008 + C# + .Net 3.5 + ASP.Net + IIS 7.0 to develop a Windows Forms application at client side to upload a file, and at server side I receive this file using an aspx file.
I find my client side application will hang after click the button to trigger upload event. Any ideas what is wrong and how to solve? Thanks!
Client side code,
public partial class Form1 : Form
{
private static WebClient client = new WebClient();
private static ManualResetEvent uploadLock = new ManualResetEvent(false);
private static void Upload()
{
try
{
Uri uri = new Uri("http://localhost/Default2.aspx");
String filename = #"C:\Test\1.dat";
client.Headers.Add("UserAgent", "TestAgent");
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompleteCallback);
client.UploadFileAsync(uri, "POST", filename);
uploadLock.WaitOne();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace.ToString());
}
}
public static void UploadFileCompleteCallback(object sender, UploadFileCompletedEventArgs e)
{
Console.WriteLine("Completed! ");
uploadLock.Set();
}
private static void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
Console.WriteLine("{0} uploaded {1} of {2} bytes. {3} % complete...",
(string)e.UserState,
e.BytesSent,
e.TotalBytesToSend,
e.ProgressPercentage);
// Console.WriteLine (e.ProgressPercentage);
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Upload();
}
}
Server side code:
protected void Page_Load(object sender, EventArgs e)
{
string agent = HttpContext.Current.Request.Headers["UserAgent"];
using (FileStream file = new FileStream(#"C:\Test\Agent.txt", FileMode.Append, FileAccess.Write))
{
byte[] buf = Encoding.UTF8.GetBytes(agent);
file.Write(buf, 0, buf.Length);
}
foreach (string f in Request.Files.AllKeys)
{
HttpPostedFile file = Request.Files[f];
file.SaveAs("C:\\Test\\UploadFile.dat");
}
}
you are waiting in the main windows events thread, so your GUI will be frozen.
Try this (using non static methods allows you to use the Control.Invoke method to run callbacks on the windows GUI thread and free this thread in order to redraw)
public partial class Form1 : Form
{
private static WebClient client = new WebClient();
private static ManualResetEvent uploadLock = new ManualResetEvent(false);
private void Upload()
{
try
{
Cursor=Cursors.Wait;
Uri uri = new Uri("http://localhost/Default2.aspx");
String filename = #"C:\Test\1.dat";
client.Headers.Add("UserAgent", "TestAgent");
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompleteCallback);
client.UploadFileAsync(uri, "POST", filename);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace.ToString());
this.Cursor=Cursors.Default;
this.Enabled=false;
}
}
public void UploadFileCompleteCallback(object sender, UploadFileCompletedEventArgs e)
{
// this callback will be invoked by the async upload handler on a ThreadPool thread, so we cannot touch anything GUI-related. For this we have to switch to the GUI thread using control.BeginInvoke
if(this.InvokeRequired)
{
// so this is called in the main GUI thread
this.BeginInvoke(new UploadFileCompletedEventHandler(UploadFileCompleteCallback); // beginInvoke frees up the threadpool thread faster. Invoke would wait for completion of the callback before returning.
}
else
{
Cursor=Cursors.Default;
this.enabled=true;
MessageBox.Show(this,"Upload done","Done");
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Upload();
}
}
}
And do the same thing in your progress (you could update a progressbar indicator for example).
Cheers,
Florian