Im trying to use the progress bar to track my download, the only problem the progress value changes only after the file is downloaded to the computer and not during its download.
Here is my code, any help will be appreciated.
public void DownloadZaq()
{
using (WebClient zaq = new WebClient())
{
zaq.DownloadProgressChanged += new DownloadProgressChangedEventHandler(Zaq_DownloadProgressChanged);
zaq.DownloadFileCompleted += new AsyncCompletedEventHandler(Zaq_DownloadFileCompleted);
zaq.DownloadFileAsync(new Uri(http://example.com), #"c:\to\111.jpg");
}
}
public void Zaq_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("download completed");
}
public void Zaq_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
I think that DownloadFileAsync is blocking the main thread somehow while checking the DNS. This is what I would try
WebClient zaq;
public void DownloadZaq()
{
zaq = new WebClient();
zaq.DownloadProgressChanged += new DownloadProgressChangedEventHandler(Zaq_DownloadProgressChanged);
zaq.DownloadFileCompleted += new AsyncCompletedEventHandler(Zaq_DownloadFileCompleted);
System.Threading.Tasks.Task.Run(() => // Workaround to allow Async call
{
try
{
zaq.DownloadFileAsync(new Uri(http://example.com), #"c:\to\111.jpg");
}
catch (Exception ex)
{
zag.Dispose();
}
});
}
public void Zaq_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("download completed");
zag.Dispose();
}
public void Zaq_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
Related
I am stuck and asking for your help, trying to make a software that check a txt file which is this format with CRC information and download the files inside that txt. These is just an example with same hash but in reality have different name, hash and size.
[FOLDER/FILE] [HASH] [FILESIZE]
./file1.dat f926038f 54
./Folder/file2.dat f926038f 54
./Folder/Subfolder/file3.dat f926038f 54
after I generate this type of information, I use this code to read where is the file...
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
StreamReader streamReader = new StreamReader(new WebClient().OpenRead(Import.ServerURL + Import.PatchlistName));
while (!streamReader.EndOfStream)
ListProcessor.AddFile(streamReader.ReadLine());
}
and these code to check the list of that file and write them in current folder
internal class ListProcessor
{
public static void AddFile(string File) => Import.Files.Add(new Import.File()
{
Name = File.Split(' ')[0],
Hash = File.Split(' ')[1],
Size = Convert.ToInt64(File.Split(' ')[2])
});
}
the problem is that files outside of any folders or subfolders they are downloading perfectly, but inside any folder or subfolder the download does not work.
PS: This is the order from where it starts:
Main.cs
private void Btn_Run_Click(object sender, EventArgs e)
{
if (!this.Btn_Run.Enabled)
return;
ListDownloader.DownloadList();
}
ListDownloader.cs
internal class ListDownloader
{
public static void DownloadList()
{
Common.ChangeStatus("LISTDOWNLOAD");
Common.DisableStart();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(ListDownloader.backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ListDownloader.backgroundWorker_RunWorkerCompleted);
if (backgroundWorker.IsBusy)
{
int num = (int) MessageBox.Show(Texts.GetText("UNKNOWNERROR", (object) "DownloadList isBusy"));
Application.Exit();
}
else
backgroundWorker.RunWorkerAsync();
}
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
StreamReader streamReader = new StreamReader(new WebClient().OpenRead(Import.ServerURL + Import.PatchlistName));
while (!streamReader.EndOfStream)
ListProcessor.AddFile(streamReader.ReadLine());
}
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
FileChecker.CheckFiles();
}
}
FileChecker.cs
internal class FileChecker
{
private static BackgroundWorker backgroundWorker = new BackgroundWorker();
public static void CheckFiles()
{
FileChecker.backgroundWorker.WorkerReportsProgress = true;
FileChecker.backgroundWorker.DoWork += new DoWorkEventHandler(FileChecker.backgroundWorker_DoWork);
FileChecker.backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(FileChecker.backgroundWorker_ProgressChanged);
FileChecker.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(FileChecker.backgroundWorker_RunWorkerCompleted);
if (FileChecker.backgroundWorker.IsBusy)
{
int num = (int) MessageBox.Show(Texts.GetText("UNKNOWNERROR", (object) "CheckFiles isBusy"));
Application.Exit();
}
else
FileChecker.backgroundWorker.RunWorkerAsync();
}
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Import.File file in Import.Files)
{
Import.fullSize += file.Size;
FileChecker.backgroundWorker.ReportProgress(0, (object) Path.GetFileName(file.Name));
if (!System.IO.File.Exists(file.Name) || string.Compare(Common.GetHash(file.Name), file.Hash) != 0)
{
Import.OldFiles.Add(file.Name);
}
else
{
Import.completeSize += file.Size;
FileChecker.backgroundWorker.ReportProgress(1);
}
}
}
private static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 0)
{
Common.ChangeStatus("CHECKFILE", e.UserState.ToString());
}
else
{
Common.UpdateCompleteProgress(Computer.Compute(Import.completeSize));
Common.UpdateCurrentProgress(Computer.Compute(Import.completeSize), 0.0);
}
}
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
FileDownloader.DownloadFile();
}
private enum State
{
REPORT_NAME,
REPORT_PROGRESS,
}
}
and FileDownloader.cs
internal class FileDownloader
{
private static int curFile;
private static long lastBytes;
private static long currentBytes;
private static Stopwatch stopWatch = new Stopwatch();
public static void DownloadFile()
{
if (Import.OldFiles.Count <= 0)
{
Common.ChangeStatus("CHECKCOMPLETE");
Common.UpdateCurrentProgress(100L, 0.0);
Common.UpdateCompleteProgress(100L);
Starter.Start();
}
else if (FileDownloader.curFile >= Import.OldFiles.Count)
{
Common.ChangeStatus("DOWNLOADCOMPLETE");
Common.UpdateCurrentProgress(100L, 0.0);
Common.UpdateCompleteProgress(100L);
Starter.Start();
}
else
{
if (Import.OldFiles[FileDownloader.curFile].Contains("/"))
Directory.CreateDirectory(Path.GetDirectoryName(Import.OldFiles[FileDownloader.curFile]));
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(FileDownloader.webClient_DownloadProgressChanged);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(FileDownloader.webClient_DownloadFileCompleted);
FileDownloader.stopWatch.Start();
Common.ChangeStatus("DOWNLOADFILE", Import.OldFiles[FileDownloader.curFile]);
webClient.DownloadFileAsync(new Uri(Import.ServerURL + Import.OldFiles[FileDownloader.curFile]), Import.OldFiles[FileDownloader.curFile]);
}
}
private static void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
FileDownloader.currentBytes = FileDownloader.lastBytes + e.BytesReceived;
Common.UpdateCompleteProgress(Computer.Compute(Import.completeSize + FileDownloader.currentBytes));
Common.UpdateCurrentProgress((long) e.ProgressPercentage, Computer.ComputeDownloadSpeed((double) e.BytesReceived, FileDownloader.stopWatch));
}
private static void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
FileDownloader.lastBytes = FileDownloader.currentBytes;
Common.UpdateCurrentProgress(100L, 0.0);
++FileDownloader.curFile;
FileDownloader.stopWatch.Reset();
FileDownloader.DownloadFile();
}
}
I am having some timing issues with the following code. Basically I have "recordingOn", when True, it's suppose to start writing frames to file. In the below program, when I sometimes do Stop_Button_Click, I get an exception on "writer1.Write(frame1);" line, this is likely because it's doing so after I've already done dispose(). How do I synchronize this? thanks!
private bool recordingOn = false;
private void ConnectCameras_Button_Click(object sender, EventArgs e)
{
if (!captureInProgress) //Start cameras streaming
{
camera1Capture.ImageGrabbed += ProcessFrame;
camera1Capture.Start();
}
else //Stop cameras streaming
{
camera1Capture.Stop();
imageBox1.Image = null;
camera1Capture.ImageGrabbed -= ProcessFrame;
}
captureInProgress = !captureInProgress;
}
private void ProcessFrame(object sender, EventArgs arg)
{
camera1Capture.Retrieve(frame1);
imageBox1.Image = frame1;
if (recordingOn)
{
try
{
writer1.Write(frame1);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private void Stop_Button_Click(object sender, EventArgs e)
{
// Doing other stuff...
recordingOn = false;
writer1.Dispose();
}
The basic issue is of shared variable across multiple threads. Please use lock to control access to shared variable. Lock ensures that at one time only one thread can access a variable.
private bool recordingOn = false;
private static object _lock = new Object();
private void ConnectCameras_Button_Click(object sender, EventArgs e)
{
if (!captureInProgress) //Start cameras streaming
{
camera1Capture.ImageGrabbed += ProcessFrame;
camera1Capture.Start();
}
else //Stop cameras streaming
{
camera1Capture.Stop();
imageBox1.Image = null;
camera1Capture.ImageGrabbed -= ProcessFrame;
}
captureInProgress = !captureInProgress;
}
private void ProcessFrame(object sender, EventArgs arg)
{
camera1Capture.Retrieve(frame1);
imageBox1.Image = frame1;
lock (_lock)
{
if (recordingOn)
{
try
{
writer1.Write(frame1);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
private void Stop_Button_Click(object sender, EventArgs e)
{
// Doing other stuff...
lock (_lock)
{
recordingOn = false;
writer1.Dispose();
}
}
I'm not sure if invoke is the right way to use it. It's working fine but i wonder if i should use invoke or some other way to update gui controls ? And if i want to report to more then 1 gui control ?
Now i'm updating label2 and a listView controls using invoke.
When should i use invoke and when not and then how to update this gui controls without invoking ?
private string pathtosearch;
private int countfiles;
public Form1()
{
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
DirSearch(pathtosearch);
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d))
{
Invoke((MethodInvoker)delegate
{
countfiles += 1;
label2.Text = countfiles.ToString();
});
}
DirSearch(d);
}
}
catch (System.Exception excpt)
{
Invoke((MethodInvoker)delegate
{
ListViewCostumControl.lvnf.Items.Add(excpt.Message);
});
}
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
label1.Text = folderBrowserDialog1.SelectedPath;
pathtosearch = folderBrowserDialog1.SelectedPath;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (textBox1.TextLength > 0)
backgroundWorker1.RunWorkerAsync();
}
Use the ReportProgress method to send Message to UI and ProgressChanged event to handle the message.
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
var ex = e.UserState as Exception;
if(ex!= null)
ListViewCostumControl.lvnf.Items.Add(ex.Message);
else
label2.Text = e.ProgressPercentage.ToString();;
}
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d))
backgroundWorker1.ReportProgress(countfiles++);
DirSearch(d);
}
}
catch (System.Exception excpt)
{
backgroundWorker1.ReportProgress(countfiles, excpt);
}
}
ReportProgress can overloaded with two argument: one numeric to report simple "Progress", an thesecond called UserData of type object. if you want send rich information, insert in this argument your custom object or any other existing with the required properties, and on the other side - in ProgressChanged event, "cast" it again to the appropriate type, example:
ReportProgress:
backgroundWorker1.ReportProgress(countfiles, Tuple.Create(currFile, "Copying...", timeRem));
ProgressChanged event:
var data = e.UserState as Tuple<string, string, TimeSpan>;
I'm sending multiple files to my wrapper which sends files to ftp.I have to get the progress of the upload, so i have to use asycn method for uploading.The problem is, how can i call the uploader one by one, but also get the progress report?
Here's a solution if you want to wait for each file:
class FileUploader
{
private readonly Uri _destination;
public FileUploader(Uri destination)
{
_destination = destination;
}
public void UploadFiles(IEnumerable<string> fileNames)
{
foreach (var fileName in fileNames)
{
UploadFile(fileName);
}
}
private void UploadFile(string fileName)
{
var tcs = new TaskCompletionSource<bool>();
using (var client = new WebClient())
{
client.UploadProgressChanged += UploadProgressChangedHandler;
client.UploadFileCompleted += (sender, args) => UploadCompletedHandler(fileName, tcs, args);
client.UploadFileAsync(_destination, fileName);
tcs.Task.Wait();
}
}
private void UploadCompletedHandler(string fileName, TaskCompletionSource<bool> tcs, UploadFileCompletedEventArgs e)
{
if (e.Cancelled)
{
tcs.TrySetCanceled();
}
else if (e.Error != null)
{
tcs.TrySetException(e.Error);
}
else
{
tcs.TrySetResult(true);
}
}
private void UploadProgressChangedHandler(object sender, UploadProgressChangedEventArgs e)
{
// Handle progress, e.g.
System.Diagnostics.Debug.WriteLine(e.ProgressPercentage);
}
}
You have to subscribe to the UploadProgressChanged event:
var client = new WebClient();
client.UploadProgressChanged += (s, e) => System.Diagnostics.Debug.WriteLine(e.ProgressPercentage);
client.UploadFileAsync(new Uri("ftp://server/directory"), #"C:\temp\file.txt");
client.UploadFileCompleted += (s, e) => Task.Factory.StartNew(client.Dispose);
Okay so I have ran into a problem, I have created a server which handles a single client and now I want to kick it up a notch and have it handle multiple clients at one time.
I have looked and tried to do this using HashTables and also Async but I keep getting stuck, this is a grey area for me as I have only just recently started dealing with sockets etc...
I wondered if anyone had a way of doing it?
Any advise will be taken on board.
This is my server code(If it helps).
namespace ChatServer
{
delegate void UpdateTextBox(string msg);
public partial class Form1 : Form
{
private TcpListener ConnectionListener;
private BinaryReader MessageReader;
private BinaryWriter MessageWriter;
private Socket ClientConnection;
private NetworkStream DataStream;
private Thread ListeningThread;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
try
{
IPAddress.Parse(textBox3.Text);//
ListeningThread = new Thread(new ThreadStart(ListenForConnections));
ListeningThread.Start();
}
catch (Exception)
{
MessageBox.Show("Wrong Ip Address");
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
if (ClientConnection.Connected)
{
MessageWriter.Write(textBox2.Text);
textBox2.Clear();
}
}
catch (Exception)
{
MessageBox.Show("no client is connected");
}
}
private void textBox2_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
try
{
if (ClientConnection.Connected)
{
MessageWriter.Write(textBox2.Text);
textBox2.Clear();
}
}
catch (Exception)
{
MessageBox.Show("no client is connected");
}
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
System.Environment.Exit(System.Environment.ExitCode);
}
private void ListenForConnections()
{
try
{
ConnectionListener = new TcpListener(IPAddress.Parse(textBox3.Text), 80);
ConnectionListener.Start();
ChangeTextBoxContent("Listening For Connections");
ClientConnection = ConnectionListener.AcceptSocket();
DataStream = new NetworkStream(ClientConnection);
MessageReader = new BinaryReader(DataStream);
MessageWriter = new BinaryWriter(DataStream);
ChangeTextBoxContent("Connection Received");
HandleConnection();
MessageReader.Close();
MessageWriter.Close();
DataStream.Close();
ClientConnection.Close();
}
catch (Exception)
{
MessageBox.Show("Unable to connect, wrong ip address");
}
}
private void HandleConnection()
{
string message;
do
{
try
{
message = MessageReader.ReadString();
ChangeTextBoxContent(message);
}
catch (Exception)
{
ChangeTextBoxContent("connection Lost");
break;
}
} while (true);
}
private void ChangeTextBoxContent(string tx)
{
if (textBox1.InvokeRequired)
{
Invoke(new UpdateTextBox(ChangeTextBoxContent), new object[] { tx });
}
else
{
textBox1.Text += tx + "\r\n";
}
}
}
}
Thank you in advance.
You should handle each of your connections in a separate thread. Create a loop that constantly listens for remote connections, and when a remote connection is called, create a new thread with the connection as the object parameter.