I'm writing a program that's supposed to download something off GitHub. It has a link to a raw file on GitHub. I'm using DownloadDataAsync to download it, and I have a progress bar to track how far it is in the download. It always gets to 100%, but then it does nothing.
I've been following a tutorial for a C# updater by BetterCoder (The beginning starts here and the most relevant part would be Part 9 of the series).
This is the part where it stops working properly:
private void DownloadUpdate(SaveyourUpdateXML update)
{
SharpUpdateDownloadForm form = new SharpUpdateDownloadForm(update.Uri, update.MD5, this.applicationInfo.ApplicationIcon);
Debug.WriteLine("form created");
DialogResult result = form.ShowDialog(this.applicationInfo.Context);
Debug.WriteLine("got result");
if (result == DialogResult.OK)
{
String currentPath = this.applicationInfo.ApplicationAssembly.Location;
String newPath = Path.GetDirectoryName(currentPath) + "\\" + update.FileName;
UpdateApplication(form.TempFilePath, currentPath, newPath, update.LaunchArgs);
Application.Exit();
}
}
It never gets to the "got result" part unless I cancel it. Also, this.applicationInfo.Context returns a form. However, it does say "form created".
I think there's something wrong with the way ShowDialog is used or something, but I'm not really sure what.
Edit: This is what happens when a SharpUpdateDownloadForm is created.
internal SharpUpdateDownloadForm(Uri location, String md5, Icon programIcon)
{
InitializeComponent();
if (programIcon != null)
{
this.Icon = programIcon;
}
tempFile = Path.GetTempFileName();
this.md5 = md5;
webClient = new WebClient();
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
bgWorker = new BackgroundWorker();
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
try
{
webClient.DownloadDataAsync(location, this.tempFile);
}
catch
{
this.DialogResult = DialogResult.No;
this.Close();
}
}
This is what should happen when a download is completed:
private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
this.DialogResult = DialogResult.No;
this.Close();
}
else if (e.Cancelled)
{
this.DialogResult = DialogResult.Abort;
this.Close();
}
else
{
lblProgress.Text = "Verifying Download...";
progressBar.Style = ProgressBarStyle.Marquee;
bgWorker.RunWorkerAsync(new string[] {this.tempFile, this.md5});
}
}
This is bgWorker_RunWorkerCompleted
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.DialogResult = (DialogResult)e.Result;
this.Close();
}
And bgWorker_DoWork
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
String file = ((string[])e.Argument)[0];
String updateMD5 = ((string[])e.Argument)[1];
if (Hasher.HashFile(file, HashType.MD5) != updateMD5)
e.Result = DialogResult.No;
else
e.Result = DialogResult.OK;
}
When webClient.DownloadDataAsync completes, it fires DownloadDataCompleted event, not DownloadFileCompleted - the one you registered.
The fix is, if you use webClient.DownloadDataAsync, register the DownloadDataCompleted event; Note that the 2nd argument to webClient_DownloadDataCompleted is different.
webClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(webClient_DownloadDataCompleted);
...
private void webClient_DownloadDataCompleted(Object sender, DownloadDataCompletedEventArgs e)
{
...
}
Related
I want to save richTextBox.Text every minute, when user checked save checkbox.
here checkbox event.
num_saveTime is numericUpDown control for inpute minute.
save_timer is global variable.
private void chk_save_CheckedChanged(object sender, EventArgs e)
{
if (chk_save.Checked)
{
num_saveTime.Enabled = false;
save_timer = new System.Timers.Timer();
save_timer.Elapsed += new System.Timers.ElapsedEventHandler(save_timer_Elapsed);
save_timer.Interval = 250;
save_timer.Start();
}
else
{
num_saveTime.Enabled = true;
save_timer.Stop();
}
}
and Timer Event
delegate void TimerDelegate(object sender, System.Timers.ElapsedEventArgs e);
void save_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (rtxb_PKT.InvokeRequired)
{
TimerDelegate tdel = new TimerDelegate(save_timer_Elapsed);
rtxb_PKT.Invoke(tdel, new object[] { sender, e });
}
else
{
string now_ss = DateTime.Now.ToString("ss");
if (now_ss.Equals("00"))
{
string now_mm = DateTime.Now.ToString("mm");
string save_mm = Convert.ToInt32(num_saveTime.Value).ToString("D2");
if (save_mm.Equals(now_mm))
{
string path = Application.StartupPath + #"\" + DateTime.Now.ToString("yy-MM-dd--HH-mm-sss") + ".rtf";
rtxb_PKT.SaveFile(path, RichTextBoxStreamType.RichText);
rtxb_PKT.Clear(); //----here
}
}
}
}
I want clear richTextBox after save.
But I insert .Clear() that position, it clear text before save, so file is empty...
How can I clear it after saving?
I have a similar question as last time, but no matter how much I hit my head against the wall, solution is not coming. The problem is that the message box gets created too many times, when it should only open once, unsubscribe from documentCompleted and then exit. Thanks again!
private void textBox4_TextChanged(object sender, EventArgs e)
{
if (textBox4.Text.Length >= 3)
{
timer1.Enabled = true;
}
}
private void timer1_Tick_1(object sender, EventArgs e)
{
if (textBox4.Text != "")
{
webBrowser1.ScriptErrorsSuppressed = true;
webBrowser1.Navigate("https://worldofwarcraft.com/en-gb/search?q=" + textBox4.Text);
webBrowser1.DocumentCompleted += GetImg; //sub here
}
}
private void GetImg(object sender, WebBrowserDocumentCompletedEventArgs e)
{
string img_url = "";
foreach (HtmlElement el in webBrowser1.Document.GetElementsByTagName("div"))
{
if (el.GetAttribute("className") == "Avatar-image")
{
img_url = (el.OuterHtml).Substring(el.OuterHtml.IndexOf("https"));
img_url = img_url.Substring(0, img_url.IndexOf(")"));
pictureBox1.ImageLocation = img_url;
}
else if (el.GetAttribute("className") == "Character-level")
{
textBox5.Visible = true;
label7.Visible = true;
string lvl_url = "";
lvl_url = (el.InnerHtml).Substring(3);
lvl_url = lvl_url.Substring(0, lvl_url.IndexOf("<"));
textBox5.Text = lvl_url;
DialogResult YESNO = MessageBox.Show("Is this your character?", "Select your char", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (YESNO == DialogResult.Yes)
{
// clean up
webBrowser1.DocumentCompleted -= GetImg; //unsub here
pictureBox1.Enabled = false;
timer1.Dispose();
break;
}
}
}
}
You need to either set timer1.Enabled to false or call timer1.Stop() as soon as you enter the timer1_Tick_1 method, or the timer will keep firing and calling your method every time.
In my Windows Form Application, certain directories are copied on user request. Currently copying these directories is running on UI thread as a result, I am not able see any progress of the process.
Currently the copy function is trigger my following code.
private void button5_Click(object sender, EventArgs e)
{
string[] str = comboBox2.Text.Split(' ');
string username = str[2].Replace("[", "").Replace("]", "");
label3.Text = comboBox3.Text;
DialogResult result = MessageBox.Show("Do you want to copy " + comboBox3.Text + " mozilla profile for " + username + " to Selected Servers?", "Confirmation", MessageBoxButtons.YesNoCancel);
if (result == DialogResult.Yes)
{
if (myCheck.Checked == true)
{
string path = getPath(comboBox3.Text);
try
{
string source = path + "\\Appdata";
string dest = "\\\\192.168.1.40\\C$\\Users\\" + username + "\\AppData\\Local\\Mozilla";
Copy(#source, #dest);
}
}
}
}
Copy functions has following Code.
public void Copy(string sourceDirectory, string targetDirectory)
{
DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);
//Gets size of all files present in source folder.
GetSize(diSource, diTarget);
maxbytes = maxbytes / 1024;
progressBar1.Maximum = maxbytes;
CopyAll(diSource, diTarget);
}
public void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
if (Directory.Exists(target.FullName) == false)
{
Directory.CreateDirectory(target.FullName);
}
foreach (FileInfo fi in source.GetFiles())
{
fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
total += (int)fi.Length;
copied += (int)fi.Length;
copied /= 1024;
progressBar1.Visible = true;
progressBar1.Step = copied;
progressBar1.PerformStep();
label14.Visible = true;
label14.Text = (total / 1048576).ToString() + "MB of " + (maxbytes / 1024).ToString() + "MB copied";
label14.Refresh();
}
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
public void GetSize(DirectoryInfo source, DirectoryInfo target)
{
if (Directory.Exists(target.FullName) == false)
{
Directory.CreateDirectory(target.FullName);
}
foreach (FileInfo fi in source.GetFiles())
{
maxbytes += (int)fi.Length;//Size of File
}
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
GetSize(diSourceSubDir, nextTargetSubDir);
}
}
My code is working perfectly but i am not able to see the progress and not able to see the update in Label.
Can somebody help me to run this copy in new thread so that I can see the progress in progress bar.
Here's a simple example to use background worker.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Shown += new EventHandler(Form1_Shown);
// To report progress from the background worker we need to set this property
backgroundWorker1.WorkerReportsProgress = true;
// This event will be raised on the worker thread when the worker starts
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
// This event will be raised when we call ReportProgress
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
}
void Form1_Shown(object sender, EventArgs e)
{
// Start the background worker
backgroundWorker1.RunWorkerAsync();
}
// On worker thread so do our thing!
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Your background task goes here
for (int i = 0; i <= 100; i++)
{
// Report progress to 'UI' thread
backgroundWorker1.ReportProgress(i);
// Simulate long task
System.Threading.Thread.Sleep(100);
}
}
// Back on the 'UI' thread so we can update the progress bar
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// The progress percentage is a property of e
progressBar1.Value = e.ProgressPercentage;
}
}
You can do the CopyAll in Do_Work and Report progress to show the progress on UI in a progress bar.
Not going to wrap it up for you but I think the following might get you on the right track.
Given you have "standard" :) button1 and progressBar1 you get nice non-blocking UI update using e.g. Task and BeginInvoke().
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 5;
Task.Factory.StartNew(() =>
{
for (int i = 0; i <= 5; i++)
{
int progress = i;
progressBar1.BeginInvoke((Action)(() =>
{
progressBar1.Value = progress;
}));
Thread.Sleep(250);
}
});
}
Try this pseudo code:
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.WorkerReportsProgress = true;
bw.DoWork +=
new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged +=
new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
private void button5_Click(object sender, EventArgs e)
{
// rest of the code above this...
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
// rest of the code above this...
Copy(#source, #dest);
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Visible = true;
progressBar1.Step = copied;
progressBar1.PerformStep();
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Completed");
}
I am trying to detect the internet connection, if the internet connection is available and it is connected, it will continue, otherwise it will throw message box says that the connection is not available.
What I am encounter is whether the internet connection is connected or not connected, the code will continue.
Here is the code:
** The program will continue to worker_ProgressChanged, even though there is no internet connection available **
public CheckUpdates()
{
InitializeComponent();
bool checkConnection = CheckConnection.IsConnectedToInternet();
progressBar1.Style = ProgressBarStyle.Marquee;
if (checkConnection == true)
{
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(worker_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
}
else
{
System.Media.SoundPlayer _sound = new System.Media.SoundPlayer(#"C:\Windows\Media\Windows Notify.wav");
_sound.Play();
DialogResult _dialogResult = MessageBox.Show("No connection available, please check your internet connection!", "No connection");
if (_dialogResult == DialogResult.OK)
{
this.Hide();
this.Close();
}
}
}
private void CheckUpdates_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
if (e.ProgressPercentage.Equals(100))
{
System.Media.SoundPlayer _sound = new System.Media.SoundPlayer(#"C:\Windows\Media\Windows Notify.wav");
_sound.Play();
DialogResult _dialogResult = MessageBox.Show("No updates were available!", "No updates");
if (_dialogResult == DialogResult.OK)
{
this.Hide();
this.Close();
}
}
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_timer.Enabled = true;
_timer.Tick += new EventHandler(Timer_Tick);
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i++)
{
backgroundWorker1.ReportProgress(i);
System.Threading.Thread.Sleep(100);
}
}
void Timer_Tick(object sender, EventArgs e)
{
_timer.Enabled = false;
}
class CheckConnection
{
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
public static bool IsConnectedToInternet()
{
int Desc;
return InternetGetConnectedState(out Desc, 0);
}
}
Your answer much appreciated!
Thank you very much!
Because you call backgroundWorker1.RunWorkerAsync(); in the event WelcomeScreen_Load or in the event CheckUpdates_Load without checking if the Internet is connected or not. (Probably the worker_ProgressChanged is defined at design time withing the backgroundWorkder properties)
These events doesn't seems to be related to a Form.Load event handler because your class doesn't derive from Form. However it seems clear that you need to put a check there otherwise whoever triggers these events will start your background worker.
private void CheckUpdates_Load(object sender, EventArgs e)
{
if(CheckConnection.IsConnectedToInternet())
backgroundWorker1.RunWorkerAsync();
}
private void WelcomeScreen_Load(object sender, EventArgs e)
{
if(CheckConnection.IsConnectedToInternet())
backgroundWorker1.RunWorkerAsync();
}
I have the following code :
This call the second form
private void updateToolStripMenuItem_Click(object sender, EventArgs e)
{
Update fm = new Update();
fm.ShowDialog();
}
This is the constructor
public Update()
{
InitializeComponent();
}
This is the load
private void Update_Load(object sender, EventArgs e)
{
String ver = checkver();
if (ver == "update")
{
if (RemoteFileExists(dlUrl) == true)
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri(dlUrl), "");
}
else
MessageBox.Show("An error occurred. Please try later.");
}
else if (ver == "newest")
{
MessageBox.Show("You are currently using the newest version.");
this.Close();
}
else
{
this.Close();
}
}
My problem is, that when the function result is 2 or 3 the form show up for millisecond and then close (flashing). I want the form to not flash. Is it possible?
I tried to use this.Hide(), this.Visible = False but nothing helped.
EDIT: I put the original code
EDIT2: Put more code
You can hide the form before loading and then set it back to visible in your if else conditions. e.g:
MyForm myForm = new MyForm();
myForm.Opacity = 0;
myForm.Show();
And then:
if (ver == "update")
{
if (RemoteFileExists(dlUrl) == true)
{
myForm.Opacity = 100;
...
}
else
MessageBox.Show("An error occurred. Please try later.");
}
else if (ver == "newest")
{
MessageBox.Show("You are currently using the newest version.");
this.Close();
}
else
{
this.Close();
}
The best way to do so :
private void Form_Load(object sender, EventArgs e)
{
switch(funct())
{
case 2:
this.BeginInvoke(new MethodInvoker(this.Close));
break;
case 3:
this.BeginInvoke(new MethodInvoker(this.Close));
break;
default:
MessageBox.Show("Something");
}
}
You should probably do whatever check you're performing before you choose to open the form in the first place.
So something like:
if(funct() == "1")
{
var form = new Form();
form.ShowDialog();
}
I assume Update_Load is your FormLoad Handler? That is called after your form has been displayed. If you don't want to display it, that's too late. Change your updateToolStripMenuItem_Click to this:
String ver = checkver();
if (ver == "update")
{
if (RemoteFileExists(dlUrl))
{
Update fm = new Update();
fm.ShowDialog();
}
else
MessageBox.Show("An error occurred. Please try later.");
}
else if (ver == "newest")
{
MessageBox.Show("You are currently using the newest version.");
}
And change your Update_Load to:
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri(dlUrl), "");
Maybe hide it first, then only show it if funct() == "1":
private void Form_Load(object sender, EventArgs e)
{
this.Close();
if (funct() == "1")
MessageBox.Show("Something");
}
try this
private void Form_Load(object sender, EventArgs e)
{
switch(funct())
{
case 2:
this.Close();
break;
case 3:
this.Close();
break;
default:
MessageBox.Show("Something");
}
}