I am programming an application for downloading articles from an SQL Database on the internet. I have programmed the Website for managing the articles. Now I'm downloading the article List in gzip Format and then I decompress them to a xml-File. When I'm done I want to insert the articles to the mobile phone. This works great. Now I want to add an progress Bar to see the state of the insertion. I tried with Threading but this doesn't work. I'm posting some pieces of code from my application and also the progressUpdate methods.
private void btn_send_Click(object sender, EventArgs e)
{
label1.Text = "Download started";
string ArticlesURL = "URLTOSITE";
InvokeAsync(ArticlesURL);
}
private void InvokeAsync(string URL)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.AllowWriteStreamBuffering = true;
allDone.Reset();
request.BeginGetRequestStream(new AsyncCallback(ReadArticlesCallback), request);
allDone.WaitOne();
request.BeginGetResponse(new AsyncCallback(ResponseArticlesCallback), request);
}
private static void ReadArticlesCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
//End the operation.
Stream postSream = request.EndGetRequestStream(asynchronousResult);
string postData = "articles=test";
//Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//Write to the request stream.
postSream.Write(byteArray, 0, postData.Length);
postSream.Close();
allDone.Set();
}
private static void ResponseArticlesCallback(IAsyncResult asynchronousResult)
{
Form1 f = new Form1();
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse resp = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = resp.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
nbrArticles = Convert.ToInt16(responseString);
// Close the stream object.
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse.
resp.Close();
f.truncate_articles();
f.get_articles();
}
private void get_articles()
{
string url = "URLTOSITE";
int startPoint = 0;
DownloadZipFile((object)startPoint, url);
DecompressFile();
getXmlAndInsertInDB();
}
private void getXmlAndInsertInDB()
{
int total = nbrArticles;
int count = total / 100; //How much articles are 1 percent
int i = 0;
String barcode = "";
String name = "";
bool state = false;
XmlTextReader reader = new XmlTextReader("Program Files\\SmartDeviceProject1\\articles.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: //The node is an element
while (reader.MoveToNextAttribute()) //Get the attributes like barcode, lastname, firstname, pincode
switch (reader.Name)
{
case "barcode":
barcode = reader.Value.ToString();
state = false;
break;
case "name":
name = reader.Value.ToString();
state = true;
break;
}
break;
}
if (state == true)
{
cmd.CommandText = "INSERT INTO articles(barcode, name) " +
"VALUES('" + barcode + "','" + name + "');";
cmd.ExecuteNonQuery();
state = false;
i++;
if (i == count)
{
Thread t = new Thread(new ThreadStart(this.incrementProgressBar));
t.Start();
//incrementProgressBar();
i = 0;
}
}
}
reader.Close();
}
private void updateProgressBarMethod(int progress)
{
if (progressBar1.InvokeRequired)
{
//It was called from a non UI thread so we create a delegate
//and have the UI Thread call this method again
UpdateProgressBar = new UpdateProgressBarDelegate(updateProgressBarMethod);
this.Invoke(UpdateProgressBar, progress);
}
else
{
//Called from the UI Thread OK to update
//update your progress bar here
progressBar1.Value += progress;
}
}
private void incrementProgressBar()
{
//Call the method to update progress Bar on UI thread
//we do not need a delegate here that will be taken care of
//in the method
updateProgressBarMethod(1);
Application.DoEvents();
}
I think the problem is that I am using Callbacks. I have read that the Callbacks are also starting Threads. So I think the problem is there but I can't solve it.
I've found another very good site for threading with mobile applications: Updating the User Interface from a Worker Thread
Now with the new code, the debugger stops always at the same piece of code without any notification or exception :( Here is my new code:
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
this.Invoke(new EventHandler(WorkerUpdate)); //The Debugger stops here!
i = 0;
step++;
Thread.Sleep(700);
}
public void WorkerUpdate(object sender, EventArgs e)
{
this.lbl_percent.Text = this.info_percent;
this.lbl_percent.Update();
this.progressBar1.Value = step;
this.progressBar1.Update();
}
The Debugger stops at: this.Invoke(new EventHandler(WorkerUpdate));
I would suggest using the Background worker class. I had a similar problem and implemented the Background worker and it fixed my problem. Hopefully it will fix yours also
http://www.dotnetperls.com/backgroundworker
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
I found another thread discussing this and thought it would help:
Is there a BackgroundWorker replacement for .NET Compact Framework 3.5?
Your code will always hang at this point:
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
this.Invoke(new EventHandler(WorkerUpdate)); //The Debugger stops here!
i = 0;
step++;
Thread.Sleep(700);
}
Make these changes:
public delegate void MethodInvoker(); // this is not defined in CF
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
object sender = null; // make this whatever you want/need
EventArgs e = new EventArgs();
if (this.InvokeRequired) {
MethodInvoker mi = delegate { WorkerUpdate(sender, e); } };
this.BeginInvoke(mi);
} else {
WorkerUpdate(sender, e);
}
i = 0;
step++;
// Thread.Sleep(700); Why is this here?
}
This should prevent those obnoxious freezes.
Related
I am using the following function to get response of a url from web. when i place the response in message box it displays properly.when i put it in text box the programme gets stuck on that statement and doesn't move.why is it happening,as i am feeding the string(response_message) to textbox.
void message_send(int j)
{
int y = 0;
if (CONTACT_NO[j] != "")
{
string Message = "hello";
string url = "some url not mentioned here ";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 30000;
using (WebResponse response = (HttpWebResponse)request.GetResponse())
{
byte[] bytes = ReadFully(response.GetResponseStream());
response_message = System.Text.Encoding.UTF8.GetString(bytes);
// error_logs(str);
MessageBox.Show(response_message);
textBox2.Text = response_message;
}
//textBox3.Text = response_message;
}
else
{
messagebox.show("some message");
}
Since you're multithreading your update to your textbox, you need to be aware that your worker thread can't update the textbox because the textbox wasn't created on the worker thread.
To update the textbox in a thread safe way, I'd recommend the easiest way of invoking:
TextBox2.Invoke((MethodInvoker)(() => { TextBox2.Text = response_message });
I was using my this function in backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) function.which i guess is separate thread.due to which i wasn't able to access textbox1.hence i used the following method to access it.
private void SetText1(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText1);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox2.Text = text;
}
}
Mistake that i was doing i wasn't using the try catch method to check for the exception.which helps me in understanding my issue.
I've seen some great answers here and was wondering if someone could help me out.
Here's my code:
namespace expandGUIWPF
{
public static string getSHA256b64(string filepath)
{
byte[] bytes = SHA256.Create().ComputeHash(File.ReadAllBytes(filepath));
return Convert.ToBase64String(bytes);
}
private void btnRun_Click(object sender, RoutedEventArgs e)
{
{
string folder = txtFolder.Text;
string filelist = folder + "\\FileList.txt";
string[] test = Directory.GetFiles(folder, "*", System.IO.SearchOption.AllDirectories);
File.WriteAllLines(filelist, test);
int length = File.ReadLines(filelist).Count();
pBar1.Minimum = 1;
pBar1.Maximum = length;
File.WriteAllLines(filelist, test);
using (StreamReader sr = new StreamReader(filelist))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string oldfile = line;
string newfile = oldfile + ".expanded";
string oldhash = "";
string newhash = "";
try
{
ProcessStartInfo startInfo = new ProcessStartInfo(#"C:\test\test.exe", oldfile + " " + newfile);
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);
Thread.Sleep(1000);
if (File.Exists(oldfile))
{
oldhash = getSHA256b64(oldfile);
}
if (File.Exists(newfile))
{
newhash = getSHA256b64(newfile);
File.Delete(oldfile);
File.Move(newfile, oldfile);
}
pBar1.Value = pBar1.Value + 1;
txtLog.AppendText(oldfile + "\r\n Old: " + oldhash + "\r\n New: " + newhash + "\r\n");
if (!(oldhash == newhash))
{
txtLog.AppendText("Successfully expanded file \r\n");
}
else
{
txtLog.AppendText("Unable to expand file \r\n");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
}
}
}
The problem is that my progressbar isn't updating. I know a little C# but I'm a beginner to WPF and can't get my head around setting up a background worker to update my UI. Would someone be able to give me a few pointers please? Currently the app works fine, but the progressbar jumps to 100% finished and all of the text suddenly appears.
Thanks in advance!
Tom
First you'll want your background worker to handle the processes in its DoWork event. Within that event you can call the ProgressChanged event to update the progress bar. Below is an example:
private void btnRun_Click(object sender, RoutedEventArgs e)
{
if(workerThread.IsBusy == false) // Make sure someone doesn't click run multiple times by mistake
{
pBar1.Value = 0;
workerThread.RunWorkerAsync();
}
}
private void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
// Definitions and so forth
pBar1.Minimum = 0;
pBar1.Maximum = length;
int status = 0;
using (StreamReader sr = new StreamReader(filelist))
{
string line;
while ((line = sr.ReadLine()) != null)
{
// Try/Catch work here
status++;
workerThread.ReportProgress(status);
}
}
private void workerThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pBar1.Value = e.ProgressPercentage;
}
Just understand that the thread that's running the Form is the same one that will be used to update the form's controls. So if you have 'stuff' to do - like encrypting / decrypting lines from a file - you need to perform those items on another thread with a callback, otherwise the form display wont update until it's done with your stuff to do. You can raise events from inside a worker thread -- and catch them using an event handler on the main (form) thread to update the progress bar.
It seems that your UI thread is being blocked, in windows forms programming you have one message pump and while you main thread (UI) is doing something else it has to wait before it can process messages. You can fix this problem by setting up a background worker to send updates
For more information on UI thread and the message pump see this
http://www.codeproject.com/Articles/10311/What-s-up-with-BeginInvoke
For infomation on the backgroundworker thread see this
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Small Example code
// This event handler is where the time-consuming work is done.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
I'm facing another problem, my application downloads a file from a web, extracts it, deletes it and so on, it runs fine for the first run, then when it comes to downloading the next file it simply freezes the download and hangs there forever.. It's probably something with trying to open an already open connection, but I have no idea how to close it, this is my first time networking with C# and I'm self teaching.
My code:
public void start() {
if (File.Exists("Data/version.txt")) { File.Delete("Data/version.txt"); }
label1.Text = "Getting update information...";
WebClient webClient = new WebClient();
webClient.DownloadFileAsync(new Uri("http://127.0.0.1/update/version.txt"), #"Data/version.txt");
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(versionCompleted);
}
private void versioncheck() {
if (File.Exists("Main.exe"))
{
label1.Text = "Contacting update server...";
var versionInfo = FileVersionInfo.GetVersionInfo("Main.exe");
string version = versionInfo.ProductVersion;
string[] nversion = version.Split('.');
string updateversion = nversion[3];
int version = Int32.Parse(updateversion);
///////////////////////////////////////////////////////////
StreamReader sr = new StreamReader("Data/version.txt");
///////////////////////////////////////////////////////////
string readline = sr.ReadLine();
sr.Dispose();
int serverversion = Int32.Parse(readline);
if (serverversion > version) {
string filenumber = (version+1).ToString();
downloadfile(filenumber);
}
else if(serverversion == version){
label1.Text = "Game is up to date!";
startButton.Enabled = true;
}
}
else { MessageBox.Show("Unexpected Error!", "Error!"); }
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
label1.Text = "Extracting Files...";
var versionInfo = FileVersionInfo.GetVersionInfo("Main.exe");
string version = versionInfo.ProductVersion;
string[] nversion = version.Split('.');
string updateversion = nversion[3];
int version = Int32.Parse(updateversion); string nversion = (version + 1).ToString();
Process proc = Process.Start("update"+nversion+".exe"); // extract in the silent mode
proc.WaitForExit();
File.Delete("update" + nversion + ".exe");
label1.Text = "Checking for more updates...";
versioncheck();
}
private void versionCompleted(object sender, AsyncCompletedEventArgs e) {
versioncheck();
}
private void downloadfile(string filenumber)
{
try
{
//MessageBox.Show("Download working");
System.Net.WebClient webClient = new System.Net.WebClient();
webClient.OpenRead("http://127.0.0.1/Update/update" + filenumber + ".exe");
Int64 bytes_total = Convert.ToInt64(webClient.ResponseHeaders["Content-Length"]);
string updatelength = Convert.ToString((bytes_total / 1024).ToString());
label2.Text = "File size:" + updatelength + "KB";
////////////////////////////////////////////////////
label1.Text = "Downloading Update...";
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri("http://127.0.0.1/Update/update" + filenumber + ".exe"), #"update"+filenumber+".exe");
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.Dispose();
}
catch (WebException )
{
MessageBox.Show("Connection error!", "Error!");
Application.Exit();
}
catch (IOException)
{
MessageBox.Show("Unknown Error!", "Error!");
Application.Exit() ;
}
}
If u use async operation u gonne need to use the async and await keywords.
U need to dispose or close your webclient when it is done downloading or failing.
As b1tsh1ft stated best thing is to use the using statement.
string version = versionInfo.ProductVersion;
string[] nversion = version.Split('.');
int version = Int32.Parse(updateversion);
string nversion = (version + 1).ToString();
Isn't your VS not giving a conflicting error in your editor about this ?
First you should put WebClient in a using block because it implements IDisposable
using(var webClient = new WebClient())
{
// do work here
webClient.DownloadFile(..)
}
Don't use the async version. An exception is likely being thrown and is lost on the other thread. Test and make it work regularly first.
Also put your StreamReader (or anything implementing IDisposable) in a using() statement. It is more reliable then manually calling dispose because it disposes even on failure.
I'm writing a very simple bulk download program in c# that reads a .txt file of URLs to download. I've set it up with a global Thread and delegate for updating the GUI, and the pressing of the "Begin" button creates and starts that thread. What I want to do is have a "Pause" button that enables me to pause the download until I hit the "Resume" button. How do I do this?
The relevant code:
private Thread thr;
private delegate void UpdateProgressCallback(int curFile);
private void Begin_btn_Click(object sender, EventArgs e)
{
thr = new Thread(Download);
thr.Start();
}
private void Pause_btn_Click(object sender, EventArgs e)
{
Pause_btn.Visible = false;
Resume_btn.Visible = true;
//{PAUSE THREAD thr}
}
private void Resume_btn_Click(object sender, Eventargs e)
{
Pause_btn.Visible = true;
Resume_btn.Visible = false;
//{RESUME THREAD thr}
}
public void Download()
{
//Download code goes here
}
Obviously, I am NOT using a Worker, and I really don't wish to unless you can show me how to get it to work (I don't really understand workers). Any help would be appreciated.
If you use System.Net.WebClient.DownloadFile() or System.Net.WebClient.DownloadFileAsync() method then you cannot pause the download. The difference between these methods is that the latter method will start an asynchronous download so you will not need to create a separate thread yourself if you use this method. Unfortunately, downloads executed with either method cannot be paused or resumed.
You need to use System.Net.HttpWebRequest. Try something like this:
class Downloader
{
private const int chunkSize = 1024;
private bool doDownload = true;
private string url;
private string filename;
private Thread downloadThread;
public long FileSize
{
get;
private set;
}
public long Progress
{
get;
private set;
}
public Downloader(string Url, string Filename)
{
this.url = Url;
this.filename = Filename;
}
public void StartDownload()
{
Progress = 0;
FileSize = 0;
commenceDownload();
}
public void PauseDownload()
{
doDownload = false;
downloadThread.Join();
}
public void ResumeDownload()
{
doDownload = true;
commenceDownload();
}
private void commenceDownload()
{
downloadThread = new Thread(downloadWorker);
downloadThread.Start();
}
public void downloadWorker()
{
// Creates an HttpWebRequest with the specified URL.
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
FileMode filemode;
// For download resume
if (Progress == 0)
{
filemode = FileMode.CreateNew;
}
else
{
filemode = FileMode.Append;
myHttpWebRequest.AddRange(Progress);
}
// Set up a filestream to write the file
// Sends the HttpWebRequest and waits for the response.
using (FileStream fs = new FileStream(filename, filemode))
using (HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse())
{
// Gets the stream associated with the response.
Stream receiveStream = myHttpWebResponse.GetResponseStream();
FileSize = myHttpWebResponse.ContentLength;
byte[] read = new byte[chunkSize];
int count;
while ((count = receiveStream.Read(read, 0, chunkSize)) > 0 && doDownload)
{
fs.Write(read, 0, count);
count = receiveStream.Read(read, 0, chunkSize);
Progress += count;
}
}
}
}
I used some code from HttpWebRequest.GetResponse page on MSDN.
Instead of stopping the thread on Pause and starting a new one on Resume, you can also change the while loop to wait until download is resumed as following:
while ((count = receiveStream.Read(read, 0, chunkSize)) > 0)
{
fs.Write(read, 0, count);
count = receiveStream.Read(read, 0, chunkSize);
Progress += count;
while(!doDownload)
System.Threading.Thread.Sleep(100);
}
The up-side is that you may be able to re-use the same thread. The down-side is that the connection may timeout and become closed. In the latter case, you will need to detect this and re-connect.
You may also want to add an event for when the donwload is completed.
Okay I need help, again! For some reason it is not working, no idea why.. nothing even appears on my catch request..
public void load(object sender, DoWorkEventArgs e)
{
int repeat = 1;
int proxyIndex = 1;
if (listBox1.Items.Count == proxyIndex) //If we're at the end of the proxy list
{
proxyIndex = 0; //Make the selected item the first item in the list
}
try
{
int i = 0;
while (i < listBox1.Items.Count)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(textBox1.Text);
string proxy = listBox1.Items[1].ToString();
string[] proxyArray = proxy.Split(':');
WebProxy proxyz = new WebProxy(proxyArray[0], int.Parse(proxyArray[1]));
request.Proxy = proxyz;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string str = reader.ReadToEnd();
}
}
/*HttpWebRequest request = (HttpWebRequest)WebRequest.Create(textBox1.Text);
string proxy = listBox1.Items[i].ToString();
string[] proxyArray = proxy.Split(':');
WebProxy proxyz = new WebProxy(proxyArray[0], int.Parse(proxyArray[1]));
request.Proxy = proxyz;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string str = reader.ReadToEnd();
Thread.Sleep(100);
{
if (str != null)
{
listBox2.Items.Add("Starting connection.");
Thread.Sleep(1000);
{
listBox2.Items.Add("Waiting..");
Thread.Sleep(500);
{
listBox2.Items.Add("Connection closed.");
repeat++;
continue;
}
}
}
else if (str == null)
{
listBox2.Items.Add("Reply was null, moving on.");
proxyIndex++;
repeat++;
}
}
*/
}
}
catch (Exception ex) //Incase some exception happens
{
MessageBox.Show(ex.Message);
return;
// listBox2.Items.Add("Error:" + ex.Message);
}
}
How can I get it to work?
It looks like you're trying to use a BackgroundWorker to perform this operation, and in the absence of any more detailed information on what isn't working, I'd guess it's because you aren't assigning any result or errors which can be picked up by main thread.
You should assign the results of the request in the case of success:
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
e.Result = reader.ReadToEnd();
}
Since you seem to be making multiple requests you should probably make the result a List<string> or similar.
You should remove the try/catch block and deal with any errors in the RunWorkerCompleted event of the BackgroundWorker:
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
MessageBox.Show("Error in async operation: " + ex.Message);
}
else
{
//process results
}
}