So I made a software that can download strings from url. Here is my code:
private void button1_Click(object sender, EventArgs e)
{
if (radioButton1.Checked)
{
var accounts = new WebClient().DownloadString("https://pastebin.pl/view/raw/sample").Split('\n');
textBox1.Text = accounts[new Random().Next(0, accounts.Length)];
}
How can I make custom progress bar made by text, such that only text will show for progressing the download? example:
When the download is 10% I want to put on text progressbar (Status: requesting database)
when it comes up to 50% I want to put on text progressbar (Status: getting information)
when it comes 100% (Status: completed)
My Full Code
My Ui
you should use async method to download
private void button1_Click(object sender, EventArgs e)
{
if (radioButton1.Checked)
{
Download(new Uri("https://pastebin.pl/view/raw/sample"));
}
else if (radioButton2.Checked)
{
Download(new Uri("https://pastebin.pl/view/raw/sample2"));
}
else if (radioButton3.Checked)
{
Download(new Uri("https://pastebin.pl/view/raw/sample4"));
}
else
{
MessageBox.Show(this, "select radio btn");
}
}
private void Download(Uri uri)
{
Thread thread = new Thread(() =>
{
WebClient client = new WebClient();
client.DownloadProgressChanged += Client_DownloadProgressChanged1;
client.DownloadStringCompleted += Client_DownloadStringCompleted;
client.DownloadStringAsync(uri);
});
thread.Start();
}
private void Client_DownloadProgressChanged1(object sender, DownloadProgressChangedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate {
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
if(percentage >=10 && percentage <50)
{
textBox1.Text ="message for 10%";
}
else if if(percentage >=50 && percentage <100)
{
textBox1.Text ="message for 50%";
}
else
{
textBox1.Text ="completed";
}
// you can use to show to calculated % of download
});
}
private void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
BeginInvoke((MethodInvoker)delegate
{
var accounts = e.Result.Split('\n');
textBox1.Text = accounts[new Random().Next(0,accounts.Length)];
});
}
WebClient has been deprecated in favor of HttpClient, but here goes.
You should use Progress<T> to report back progress.
You can define an extension method like:
public static class WebClientExtensions
{
public static async Task<string> DownloadStringTaskAsync(
this WebClient webClient,
string address,
IProgress<int> progress)
{
try
{
webClient.DownloadProgressChanged += downloadProgressChanged;
return await webClient.DownloadStringTaskAsync(address);
}
finally
{
webClient.DownloadProgressChanged -= downloadProgressChanged;
}
void downloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progress.Report(e.ProgressPercentage);
}
}
}
and use it like this:
private async void button1_Click(object sender, EventArgs e)
{
if (radioButton1.Checked)
{
var text = await new WebClient()
.DownloadStringTaskAsync(
"https://pastebin.pl/view/raw/sample",
new Progress<int>(p => /* report progress */));
var accounts = text.Split('\n');
textBox1.Text = accounts[new Random().Next(0, accounts.Length)];
}
}
Related
I'm having an issue getting a progressbar to show download progress. The files are downloading without issue, but something is causing my progressbar to not update and I can't figure out why.
I've tried setting the progressBar value manually in the download and wc_DownloadProgressChanged method, but the only place it actually changes is the Form1_Load method.
using System;
using System.Windows.Forms;
using System.Threading;
namespace Launch
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Downloader downloader = new Downloader();
ThreadStart job = new ThreadStart(downloader.download);
Thread thread = new Thread(job);
thread.Start();
}
private void ProgressBar_Click(object sender, EventArgs e)
{
}
public void SetProgress(int val)
{
progressBar.Value = val;
}
public void SetVisible(bool val)
{
progressBar.Visible = val;
}
}
}
using System;
using System.Data;
using System.Net;
using Newtonsoft.Json;
namespace Launch
{
class Downloader
{
public void download()
{
WebClient client = new WebClient();
string url = "https://someurl.com/manifest.json";
string json = client.DownloadString(url);
DataSet dataSet = JsonConvert.DeserializeObject<DataSet>(json);
DataTable dataTable = dataSet.Tables["Required"];
foreach (DataRow row in dataTable.Rows)
{
string remoteUri = row["url"].ToString();
string fileName = row["name"].ToString();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadFile(remoteUri, fileName);
Console.WriteLine("Did something with " + remoteUri);
}
}
private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
var form = new Form1();
form.SetProgress(e.ProgressPercentage);
}
}
}
Would anyone be able to shed some light on what I'm doing wrong here?
EDIT:
I was able to get this working for the most part using DownloadFileAsync, but the progress bar was bouncing back and forth, I'm assuming because it's trying to calculate the progress for each individual file as bytes are received, so I'd like to get this working with DownloadFile.
The issue I'm now having with DownloadFile is that I have it running as a task but it's skipping all of the files (not downloading any of them, just prints them all out to console super fast).
Here's the code I'm using currently:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
string url = "https://someurl.com/manifest.json";
string json = client.DownloadString(url);
DataSet dataSet = JsonConvert.DeserializeObject<DataSet>(json);
DataTable dataTable = dataSet.Tables["Required"];
foreach (DataRow row in dataTable.Rows)
{
string remoteUri = row["url"].ToString();
string fileName = row["name"].ToString();
Task.Run(() => {
client.DownloadFile(remoteUri, fileName);
});
Console.WriteLine("Did something with " + remoteUri);
}
}
private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate {
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
label1.Text = "Downloaded ";
label2.Text = e.BytesReceived.ToString();
label3.Text = e.TotalBytesToReceive.ToString();
progressBar.Value = int.Parse(Math.Truncate(percentage).ToString());
});
}
Any ideas?
Use this code below :
private void Form1_Load(object sender, EventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += client_DownloadProgressChanged;
client.DownloadStringCompleted += client_DownloadStringCompleted;
Uri url = new Uri("url");
client.DownloadStringAsync(url);
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
SetVisible(false);
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
SetProgress(e.ProgressPercentage);
}
public void SetProgress(int val)
{
progressBar.Value = val;
}
public void SetVisible(bool val)
{
progressBar.Visible = val;
}
This likely should belong to https://codereview.stackexchange.com/
First of all, do not add a handler in a loop
client.DownloadProgressChanged += client_DownloadProgressChanged;
First time it will be fine, on 2nd item it will be called 2x times, on 3rd time it will be called 3 times, etc. You want to set handler once. Move it just after line:
WebClient client = new WebClient();
Second of all, each time a progress update is fired you are creating a new instance of the form. Create a private variable or property once.
private Form1 form = new Form1();
edit:
In case of UI, usually you can modify it only in the dispatcher thread that created it or use marshaling. I would just remove it as our already downloading the string async.
Also, I would not use e.ProgressPercentage, but something like:
Math.Truncate(e.BytesReceived / (double)e.TotalBytesToReceive * 100)
I am currently making a podcast client to download episodes. I have got a listView filled with the episodes for a feed and then when you double click on one it places it into a separate 'downloads' lisview which has a 'name' and a 'progress' column.
The problem I am having is trying to individually update each progress while downloading asynchronously. As I am not sure of how to keep track of the progress for each ListViewItem and how to reference it in the downloadProgressChanged function.
private void lvPodDownloads_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lvPodEpisodes.SelectedItems.Count == 1) // Check if an item is selected just to be safe
{
ListViewItem item = (ListViewItem)lvPodEpisodes.SelectedItem;
string[] epInfo = (string[])item.Tag;
txtTitle.Text = epInfo[0];
txtDesc.Text = epInfo[1];
try
{
imgFeedImage.Source = new BitmapImage(new Uri((Environment.CurrentDirectory + "\\..\\..\\feedImages\\" + epInfo[3])));
}
catch (Exception) // If it fails to set the image (Eg. It's non-existent) It will leave it blank
{
imgFeedImage.Source = null;
}
}
}
private void lvPodEpisodes_MouseDoubleClick(object sender, MouseButtonEventArgs e) // Downloading the episode in here
{
if (e.ChangedButton == MouseButton.Left) // Left button was double clicked
{
ListViewItem selected = (ListViewItem)lvPodEpisodes.SelectedItem;
string[] epInfo = (string[])selected.Tag;
Uri downloadUrl = new Uri(epInfo[2]);
List<Episode> downloading = new List<Episode>();
downloading.Add(new Episode() { Title = epInfo[0], Progress = "0%" });
lvPodDownloads.Items.Add((new Episode() { Title = epInfo[0], Progress = "0%" }));
using (WebClient client = new WebClient())
{
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
}
}
}
static int intDownloadProgress = new int();
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
intDownloadProgress = e.ProgressPercentage;
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Download completed!");
}
This is a code sample of the downloading section of the program.
Here is an image of what I have so far:
https://s33.postimg.cc/gthzioxlr/image.png
You should add an extra argument to your ProgressChanged method.
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e, Episode curEpisode)
{
curEpisode.Progress = $"{e.ProgressPercentage} %";
}
And to modify the handler setting like that:
List<Episode> downloading = new List<Episode>();
var newEpisode = new Episode() { Title = epInfo[0], Progress = "0%" };
downloading.Add(newEpisode);
lvPodDownloads.Items.Add(newEpisode);
using (WebClient client = new WebClient())
{
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler((sender, e) => ProgressChanged(sender, e, newEpisode));
}
The static property intDownloadProgress is then useless.
You should also think about using an observable collection for the episode list and using it for the binding via the XAML code.
I just tried to write code for a progress bar with webclient
Please see my code.
private void button2_Click(object sender, EventArgs e)
{
if (textBox1.Text == "")
{
MessageBox.Show("Invalid Php Url");
}
else if (Uri.IsWellFormedUriString(textBox1.Text, UriKind.Absolute) == false)
{
MessageBox.Show("Invalid Php Url");
}
else
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCallBack2);
client.DownloadFile(textBox1.Text, #"D:\test\test.zip");
}
void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
this.label6.Text = e.ProgressPercentage.ToString();
}
void DownloadFileCallBack2(object sender, AsyncCompletedEventArgs c)
{
MessageBox.Show("Download Completed");
}
But the event is not calling why?
is this because of the background worker or any other issues?
Please help me.
Best regards,
I think it is because the progress updated is called on a background thread and not the UI thread. Try passing in the webclient to the DoWork thread:
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCallBack2);
backgroundWorker1.RunWorkerAsync(client);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
WebClient client = (WebClient)e.Argument;
client.DownloadFile(textBox1.Text, #"D:\test\test.zip");
}
Your Progress Bar must be of the following conditions :
-Accurate
-Responsive and smooth
-Precise
-Appropriate
This is how I create a thread that does domething reps times:
protected virtual void RedButtonClicked(object sender, System.EventArgs e)
{
Nuker n = new Nuker(target, reps);
bombThread = new Thread(new ThreadStart(n.nuke));
bombThread.Start();
}
The thread class:
public class Nuker
{
private string target;
private int reps;
//...
public void nuke()
{
for(int i=0; i<reps; ++i)
{
ICBM.nuke(target);
Thread.Sleep(5500);
}
System.Console.WriteLine("Done.");
}
}
(I create a new class to store some variables since I can't pass these in ThreadStart().)
Now I would like to have a simple visualisation of the process, let's say printing the current repetition in a text field on a form. How would I use the i from the loop to do that?
In the simplest form you proved a callback in the Nuker class
public Nuker(string target, int reps, Action reportCallback){..}
In the loop you just call reportCallback(i);
Nuker n = new Nuker(target, reps, ReportMethod);
with
private void ReportMethod(int currentIdx)
{
if (InvokeRequired) // Invoke if UI update
...
}
But, probably you want to use the BackgroundWorker that has build in methods for reporting progress on the UI thread. Just check the examples on MSDN.
you can do it with a backgroundworker, it´s one of the easiest threads :-)
below i have post you a sample that i have createt to teach some friends the use of the backgroundworker ;-)
private BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
public void buttonStart_Click(object sender, EventArgs e)
{
if (bw.IsBusy != true)
bw.RunWorkerAsync(12); //Start
}
public int Pils(int i)
{
Thread.Sleep(2000);
bw.ReportProgress(70, "In the middle of the work..");
Thread.Sleep(2000);
bw.ReportProgress(90, "Returning the result..");
Thread.Sleep(2000);
return (2 * i);
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
bw.ReportProgress(20, "Waiting for cancel..");
Thread.Sleep(2000);
if ((bw.CancellationPending == true))
e.Cancel = true;
else
{
bw.ReportProgress(50, "Starting process..");
e.Result = Pils((int)e.Argument);
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bw.ReportProgress(100, "Work done..");
if ((e.Cancelled == true))
textBox1.Text = "Canceled!";
else if (e.Error != null)
textBox1.Text = ("Error: " + e.Error.Message);
else textBox1.Text = e.Result.ToString();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
bw.CancelAsync();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
listBox1.Items.Add((e.ProgressPercentage.ToString() + "%") + " - " + e.UserState as String);
}
url to the blogpost: link
using System;
using System.ComponentModel;
using System.Net;
using System.Windows.Forms;
using Ionic.Zip;
namespace downloader
{
public partial class GUI : Form
{
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
public GUI()
{
InitializeComponent();
}
private void Download_Click(object sender, EventArgs e)
{
label1.Text = ("Downloading...");
WebClient x = new WebClient();
x.DownloadProgressChanged += new DownloadProgressChangedEventHandler(x_DownloadProgressChanged);
x.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(x_DownloadFileCompleted);
x.DownloadFileAsync(new Uri("http://google.com/"), desktop + "\\index.html");
download.Enabled = false;
}
void x_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
label2.Text = null;
label1.Text = "Download Complete.";
MessageBox.Show("Download Done.", "Done!");
}
public void x_DownloadProgressChanged(Object sender, DownloadProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
this.Text = ":: Kyle :: " + e.ProgressPercentage + "%";
label2.Text = e.BytesReceived + " bytes saved.";
}
public void unzip(String zFile)
{
Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(zFile);
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(zip_ExtractProgress);
zip.ExtractAll(desktop, ExtractExistingFileAction.OverwriteSilently);
zip.Dispose();
zip = null;
}
public void zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten)
{
this.label2.Text = e.BytesTransferred.ToString(); //unsafe also?
}
else if (e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry)
{
this.label3.Text = e.CurrentEntry.FileName; //unsafe
}
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
unzip(desktop + "\\Client.zip");
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button1.Enabled = true;
MessageBox.Show("Done Unzipping.");
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
}
}
How do I fix my text labels? I'm using a backgroundWorker and it works without the labels but when I have em it keeps saying Cross-thread operation not valid: Control 'label3' accessed from a thread other than the thread it was created on.
You should report the progress by calling the BackgroundWorker's ReportProgress method.
Alternatively, you can run on the UI thread by calling BeginInvoke.