I have a traffic exchange website and I want to convert it into an windows application using C# winform with Awesomium 1.7.5.
The basic setup is ready but there is a problem with Awesomium.
After visiting a few websites slows down and the freezes entirely ( Not Responding ).
public Form1()
{
InitializeComponent();
Text = "Traffic Exchange";
WindowState = FormWindowState.Maximized;
timer1 = new System.Windows.Forms.Timer();
timer1.Tick += new EventHandler(timer1_Tick);
int user_id = Properties.Settings.Default.user_id;
string user_id_s = user_id.ToString();
toolStripLabel2.Text = user_id_s;
if (Properties.Settings.Default.user_id == 0)
{
toolStripLabel3.Visible = true;
toolStripButton3.Visible = false;
}
else
{
toolStripButton3.Visible = true;
toolStripLabel3.Visible = false;
}
}
private void toolStripButton3_Click_1(object sender, EventArgs e)
{
// starting the traffic traffic exchange
LoadUrl();
StartTimer();
}
private void LoadUrl()
{
try
{
string MyConnection2 = "*******";
string Query = "select * from ****** where status = 1 AND credits > 5 ORDER BY rand() LIMIT 1";
MySqlConnection MyConn2 = new MySqlConnection(MyConnection2);
MySqlCommand MyCommand2 = new MySqlCommand(Query, MyConn2);
MyConn2.Open();
using (MySqlDataReader DR = MyCommand2.ExecuteReader())
{
while (DR.Read())
{
string WebURL = Convert.ToString(DR.GetValue(*));
string WebSurfSec = Convert.ToString(DR.GetValue(*));
int result = Convert.ToInt32(WebSurfSec);
int sec_to_mil = result * 1000;
toolStripLabel5.Text = WebSurfSec;
//toolStripStatusLabel2.Text = result.ToString();
//toolStripStatusLabel3.Text = sec_to_mil.ToString();
webControl3.Source = new Uri(WebURL);
toolStripTextBox1.Text = WebURL;
toolStripLabel6.Text = toolStripTextBox1.Text;
timer1.Interval = sec_to_mil; // in miliseconds
}
}
MyConn2.Close();
// WebCore.ReleaseMemory();
// webControl3.Update();
// Thread.Sleep(500);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
LoadUrl();
}
private void StartTimer()
{
timer1.Start();
}
So LoadUrl() it's a loop. When the app is started loads in the traffic exchange website, a little bit slow but it works and you can go form a page to another without freezing but when the exchange is in action ( LoadUrl() ) after 5 minutes the app is dead.
I've been searching for a solution all day and ended up with nothing, couldn't find a solution the problem.
The timer should not be recreated each time you loop. What is happening is that you are creating multiple event handlers each time you loop. Creating the handler once in the constructor and starting the timer in the button click routine is the right way.
You can change the interval inside the loop, but avoid adding another Start() method call there.
Related
So I have a basic WPF application, that OnStartup creates a DispatcherTimer and has a tick method that runs a basic SQL query to check the status of some arbitrary table.
It is a variable query in terms of how long it takes to execute.
If I am in the main application window, when the background DispatcherTimer runs (DispatcherTimer code being within the App.xaml, not the MainWindow.xaml), the window hangs while the query runs, and as the query runs every 5 seconds, the GUI is unresponsive.
It seems a new thread is the way to go, but I am lost on where to begin. I am relatively new to C#/WPF so it's all a learning curve at the moment. How would I go about invoking my dispatcherTimer_Tickwithin a new thread, to avoid this problem?
DispatcherTimer dispatcherTimer;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow = new MainWindow();
MainWindow.Closing += MainWindow_Closing;
_notifyIcon = new System.Windows.Forms.NotifyIcon();
_notifyIcon.DoubleClick += (s, args) => ShowMainWindow();
_notifyIcon.Icon = BackgroundApplication.Properties.Resources.GTL;
_notifyIcon.Visible = true;
CreateContextMenu();
dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
// Console.WriteLine("Tick");
SqlConnection cnn;
connectionString = #"SOME_DATA_SOURCE";
cnn = new SqlConnection(connectionString);
cnn.Open();
// MessageBox.Show("Connection Open !");
// cnn.Close();
SqlCommand command;
SqlDataReader dataReader;
String sql = "";
Int16 output = 0;
sql = "SOME SQL STATEMENT";
command = new SqlCommand(sql, cnn);
dataReader = command.ExecuteReader();
while (dataReader.Read())
{
output = Int16.Parse(dataReader[""].ToString());
}
if(output > 0)
{
_notifyIcon.Icon = BackgroundApplication.Properties.Resources.RTL;
}
_notifyIcon.Text = "Current Issues: " + output;
}
Make the Tick handler async and await the long-running call:
private async void dispatcherTimer_Tick(object sender, EventArgs e)
{
await Task.Run(() =>
{
// make query here
});
// update the UI outside the Task
_notifyIcon.Text = "Current Issues: " + output;
}
Even better would be to directly call async methods, like
private async void dispatcherTimer_Tick(object sender, EventArgs e)
{
...
dataReader = await command.ExecuteReaderAsync();
...
}
I have a program that runs and starts 2 long running tasks. One of the tasks is a web scraper in which I have to use the WebBrowser ActiveX control so that I can get the rendered page. In order to use the control I have to start a thread so that I can set the apartment state for the message loop. When I do this, the proogram works fine, or at least for the first page that is fetched. Subsequent pages/calls, the webbrowser times out and it's state seems to remain at "uninitialized". In tracing my code, I never see the "HandleDestroyed" fire for the WebClient.
What do I need to do to Properly Destroy the WebBrowser control and or my own class in order for it to be reused again.
public static string AXFetch(string url, string ua)
{
TestBrowser TB = new TestBrowser();
Thread th = new Thread(() => TB.MakeLiRequest(url,ua));
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join(new TimeSpan(0, 0, 90)); //90 second timeout
SiteData = TB.DocumentText;
TB = null;
return SiteData;
}
class TestBrowser
{
public string DocumentText = "";
private bool DocCompleted = false;
public TestBrowser()
{
}
private void reset_fetch_status()
{
this.DocCompleted = false;
this.DocumentText = "";
}
public void MakeLiRequest(string url, string UA)
{
reset_fetch_status();
using (WebBrowser wb = new WebBrowser())
{
wb.Visible = false;
wb.AllowNavigation = true;
wb.ScriptErrorsSuppressed = true;
wb.DocumentCompleted += this.wb_DocumentCompleted;
wb.Navigate(url, "_self", null, "User-Agent: " + UA + "\r\n");
WaitForPage();
wb.Url = null;
wb.DocumentCompleted -= this.wb_DocumentCompleted;
}
}
private void HandleDestroyed(Object sender, EventArgs e)
{
//This never seems to fire, I don't knwo why
Logging.DoLog("You are in the Control.HandleDestroyed event.");
}
private bool WaitForPage()
{
int timer = 0;
while (this.DocCompleted == false)
{
Application.DoEvents();
System.Threading.Thread.Sleep(100);
++timer;
if (timer == (PageTimeOut * 10))
{
Console.WriteLine("WebBrowser Timeout has been reached");
Application.Exit();
return false;
}
}
return true;
}
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = (WebBrowser)sender;
if (wb.ReadyState == WebBrowserReadyState.Complete)
{
this.DocumentText = wb.DocumentText;
this.DocCompleted = true;
}
}
}
On handle destroyed will only be called by the parent form.
If you were to try to access from the webbrowser control you would get this error:
Error 1 Cannot access protected member
'System.Windows.Forms.Control.OnHandleDestroyed(System.EventArgs)' via a
qualifier of type 'System.Windows.Forms.WebBrowser'; the qualifier must be of type 'stackoverflowpost47036339.Form1' (or derived from it)
Also you are not hooking it up. But since you haven't given your web browser any parent form, It can't be called. This is how you would hook it up to the parent form.
form1.HandleDestroyed += Form1_HandleDestroyed;
}
void Form1_HandleDestroyed(object sender, EventArgs e)
{
}
I am having an issue with my program. my program will let the user select a dropdown value and after they select the dropdown value the datagridview should load with the data from a table, and then the progress bar should start the percentage 1 to 100%. Now everything in my program works the datagridview loads correctly and everything else in the program. the progress bar also works and loads but the issue comes when the user selects the dropdow combobox the progress bar takes like 15 to 20 seconds to start. I would like it to right away.
Can you see my code and see what could be the issue to why the progress bar is not starting right away?
if you need more information please let me know.
namespace DatagridViewProgressBar
{
public partial class Form1 : Form
{
//datagridview, bindingsource, data_apapter global objects variables
private DataGridView dataGridView = new DataGridView();
private BindingSource bindingSource = new BindingSource();
private SqlDataAdapter dataAdapter = new SqlDataAdapter();
DataTable dt = new DataTable();
//class objects
Databases lemars = new Databases();
Databases schuyler = new Databases();
Databases detroitlakeskc = new Databases();
public Form1()
{
InitializeComponent();
// To report progress from the background worker we set this property
dbWorker = new BackgroundWorker();
dbWorker.DoWork += new DoWorkEventHandler(dbWorker_DoWork);
dbWorker.ProgressChanged += new ProgressChangedEventHandler(dbWorker_ProgressChanged);
dbWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(dbWorker_RunWorkerCompleted);
dbWorker.WorkerReportsProgress = true;
dbWorker.WorkerSupportsCancellation = true;
}
private void btn_Exit_Click(object sender, EventArgs e)
{
this.Close();
}
private void comboBox_Database_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox_Database.SelectedItem.ToString() == "LeMars21St")
{
if (dbWorker.IsBusy != true)
{
dbWorker.RunWorkerAsync();
}
}
}
private void GetTableToDataGridView()
{
//prgBar_DataGridViewLoading
DatabaseColumns Obj = new DatabaseColumns();
String SqlcmdString = #"SELECT invoice, shipment, Project, invoiceDateTB, CreatedDate, typeName, exportedDate, statusName, total, import_status, Time_Completed, ERROR_DESCRIPTION FROM dbo.AllInvoicesInReadyStatus";
SqlDataReader reader;
int progress;
using (SqlConnection conn = new SqlConnection(lemars._LeMarsConnectionString))
{
reader = null;
SqlCommand Sqlcmd = new SqlCommand(SqlcmdString, conn);
conn.Open();
reader = Sqlcmd.ExecuteReader();
if (reader.HasRows)
{
try
{
dt.Load(reader);
for (int i = 0; i < dt.Rows.Count; i++)
{
Obj.Invoice = dt.Rows[i]["invoice"].ToString();
Obj.Shipment = dt.Rows[i]["shipment"].ToString();
Obj.Project = dt.Rows[i]["Project"].ToString();
Obj.InvoiceDateTB = Convert.ToDateTime(dt.Rows[i]["invoiceDateTB"]);
Obj.CreatedDate = Convert.ToDateTime(dt.Rows[i]["CreatedDate"]);
Obj.TypeName = dt.Rows[i]["typeName"].ToString();
Obj.ExportedDate = Convert.ToDateTime(dt.Rows[i]["exportedDate"]);
Obj.StatusName = dt.Rows[i]["statusName"].ToString();
Obj.Total = Convert.ToDecimal(dt.Rows[i]["total"]);
Obj.ImportStatus = dt.Rows[i]["import_status"].ToString();
if (!Convert.IsDBNull(dt.Rows[i]["Time_Completed"]))
{
Obj.TimeCompleted = Convert.ToDateTime(dt.Rows[i]["Time_Completed"]);
}
Obj.ErrorDescription = dt.Rows[i]["ERROR_DESCRIPTION"].ToString();
progress = i * 100 / dt.Rows.Count;
dbWorker.ReportProgress(progress);
Thread.Sleep(500);
}
}
finally
{
conn.Close();
}
}
}
}
private void dbWorker_DoWork(object sender, DoWorkEventArgs e)
{
GetTableToDataGridView();
dbWorker.ReportProgress(100);
}
private void dbWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar_GetTasks.Value = e.ProgressPercentage;
// eg: Set your label text to the current value of the progress bar
lbl_PercentageCount.Text = (progressBar_GetTasks.Value.ToString() + "%");
}
private void dbWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
dataGridView_ShowAllData.DataSource = dt;
if (e.Cancelled)
{
MessageBox.Show("Process Cancelled.");
}
else if (e.Error != null)
{
MessageBox.Show("Error occurred: " + e.Error.Message);
}
else
{
MessageBox.Show("Successful Completion.");
}
//progressBar_GetTasks.Value = 0;
}
private void btn_CancelOperation_Click(object sender, EventArgs e)
{
if (dbWorker.IsBusy)
{
dbWorker.CancelAsync();
}
}
}
}
Doing dt.Load(reader); waits for the data to fully load before continuing, Get rid of that line and replace it with a while(reader.Read()) loop.
private void GetTableToDataGridView()
{
//prgBar_DataGridViewLoading
DatabaseColumns Obj = new DatabaseColumns();
String SqlcmdString = #"SELECT invoice, shipment, Project, invoiceDateTB, CreatedDate, typeName, exportedDate, statusName, total, import_status, Time_Completed, ERROR_DESCRIPTION FROM dbo.AllInvoicesInReadyStatus";
String CountcmdString = #"SELECT count(*) FROM dbo.AllInvoicesInReadyStatus";
SqlDataReader reader;
int progress;
int total;
using (SqlConnection conn = new SqlConnection(lemars._LeMarsConnectionString))
{
reader = null;
SqlCommand Sqlcmd = new SqlCommand(CountcmdString , conn);
conn.Open();
total = (int)Sqlcmd.ExecuteScalar(); //Get the total count.
Sqlcmd.CommandText = SqlcmdString;
using(reader = Sqlcmd.ExecuteReader()) //this should be in a using statement
{
while(reader.Read())
{
object[] row = new object[reader.VisibleFieldCount];
reader.GetValues(row);
LoadSingleRowInToTable(dt, row); //I leave this to you to write.
//You can just read directly from the reader.
Obj.Invoice = reader["invoice"].ToString();
Obj.Shipment = reader["shipment"].ToString();
Obj.Project = reader["Project"].ToString();
Obj.InvoiceDateTB = Convert.ToDateTime(reader["invoiceDateTB"]);
Obj.CreatedDate = Convert.ToDateTime(reader["CreatedDate"]);
Obj.TypeName = reader["typeName"].ToString();
Obj.ExportedDate = Convert.ToDateTime(reader["exportedDate"]);
Obj.StatusName = reader["statusName"].ToString();
Obj.Total = Convert.ToDecimal(reader["total"]);
Obj.ImportStatus = reader["import_status"].ToString();
if (!Convert.IsDBNull(reader["Time_Completed"]))
{
Obj.TimeCompleted = Convert.ToDateTime(reader["Time_Completed"]);
}
Obj.ErrorDescription = reader["ERROR_DESCRIPTION"].ToString();
//Only call report progress when the progress value changes.
var newProgress = i * 100 / total;
if(progress != newProgress)
{
progress = newProgress;
dbWorker.ReportProgress(progress);
}
//Thread.Sleep(500);
}
}
}
}
UPDATE: Here is a example based on Steve's deleted answer that shows a better solution without using a DataTable.
private void dbWorker_DoWork(object sender, DoWorkEventArgs e)
{
List<DatabaseColumns> data = GetTableToList();
if (data == null) //data will be null if we canceled.
{
e.Cancel = true;
}
else
{
e.Result = data;
}
dbWorker.ReportProgress(100);
}
private void dbWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Process Cancelled.");
}
else if (e.Error != null)
{
MessageBox.Show("Error occurred: " + e.Error.Message);
}
else
{
dataGridView_ShowAllData.DataSource = e.Result; //use the result from thebackground worker, only use if not canceled or errored.
MessageBox.Show("Successful Completion.");
}
//progressBar_GetTasks.Value = 0;
}
private List<DatabaseColumns> GetTableToList()
{
List<DatabaseColumns> data = new List<DatabaseColumns>();
//prgBar_DataGridViewLoading
String SqlcmdString = #"SELECT invoice, shipment, Project, invoiceDateTB, CreatedDate, typeName, exportedDate, statusName, total, import_status, Time_Completed, ERROR_DESCRIPTION FROM dbo.AllInvoicesInReadyStatus";
String CountcmdString = #"SELECT count(*) FROM dbo.AllInvoicesInReadyStatus";
using (SqlConnection conn = new SqlConnection(lemars._LeMarsConnectionString))
{
SqlCommand Sqlcmd = new SqlCommand(CountcmdString, conn);
conn.Open();
var total = (int)Sqlcmd.ExecuteScalar();
Sqlcmd.CommandText = SqlcmdString;
int i = 0;
int progress = 0;
using (SqlDataReader reader = Sqlcmd.ExecuteReader()) //this should be in a using statement
{
while (reader.Read())
{
if (dbWorker.CancellationPending)
{
//Exit early if operation was canceled.
return null;
}
DatabaseColumns Obj = new DatabaseColumns();
//You can just read directly from the reader.
Obj.Invoice = reader["invoice"].ToString();
Obj.Shipment = reader["shipment"].ToString();
Obj.Project = reader["Project"].ToString();
Obj.InvoiceDateTB = Convert.ToDateTime(reader["invoiceDateTB"]);
Obj.CreatedDate = Convert.ToDateTime(reader["CreatedDate"]);
Obj.TypeName = reader["typeName"].ToString();
Obj.ExportedDate = Convert.ToDateTime(reader["exportedDate"]);
Obj.StatusName = reader["statusName"].ToString();
Obj.Total = Convert.ToDecimal(reader["total"]);
Obj.ImportStatus = reader["import_status"].ToString();
if (!Convert.IsDBNull(reader["Time_Completed"]))
{
Obj.TimeCompleted = Convert.ToDateTime(reader["Time_Completed"]);
}
Obj.ErrorDescription = reader["ERROR_DESCRIPTION"].ToString();
//Add the object to the list.
data.Add(Obj);
//Only call report progress when the progress value changes.
var newProgress = i * 100 / total;
if (progress != newProgress)
{
progress = newProgress;
dbWorker.ReportProgress(progress);
}
i++;
}
}
}
return data;
}
Something I had when doing my first backgroundWorker, was the GUI locking up. I made the mistake of trying to hand out every result (primnumbers in a range from 2 to selected bound) as it was found via report progress. If I had a long enough operation (it did not happen if the operation was short) I ended up overloading and locking up the GUI with write operations, making it appear I never actually added multithreading.
Now I noticed this line:
progress = i * 100 / dt.Rows.Count;
You run the progress code (and update the bar) every loop itteration, even if the percentage did not actually change. If you process 1 million itterations, that is 10000 redraws without the value actually changing. This might slow down later as hits become rarer or the GC starts interferring with optimal performance of the task so the GUI thread has "time to catch up".
You should check if the value actually changed, before writing it to the GUI. Latest in the ProgressReporting Event. But it might be possible to do something back in the loop itself.
I made some example code to showcase what I call the "GUI write overhead" problem:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}
I've created an application that patches my game servers files.
However, I've got 3 problems which I can't solve:
When downloading a new patch, it doesn't update the progressbar instantly, but refreshes it after around 30-40 seconds
I want a label to show how much mega bytes they are downloading, and how much they have so far (for example: 122Mb/750Mb
When downloading, I want a label to show ~% of how much it has downloaded so far
I am not sure how to add number 2 and 3, and the number 1 problem just seems ridiculous, because there's nothing that indicates it should refresh after 30-40 seconds in my coding (at least as far as I know)
My backgroundWorker1_DoWork:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Defines the server's update directory
string Server = "http://localhost/dl/game-updates/";
//Defines application root
string Root = AppDomain.CurrentDomain.BaseDirectory;
//Make sure version file exists
FileStream fs = null;
if (!File.Exists("version"))
{
using (fs = File.Create("version"))
{
}
using (StreamWriter sw = new StreamWriter("version"))
{
sw.Write("1.0");
}
}
//checks client version
string lclVersion;
using (StreamReader reader = new StreamReader("version"))
{
lclVersion = reader.ReadLine();
}
decimal localVersion = decimal.Parse(lclVersion);
//server's list of updates
XDocument serverXml = XDocument.Load(#Server + "Updates.xml");
//The Update Process
foreach (XElement update in serverXml.Descendants("update"))
{
string version = update.Element("version").Value;
string file = update.Element("file").Value;
decimal serverVersion = decimal.Parse(version);
string sUrlToReadFileFrom = Server + file;
string sFilePathToWriteFileTo = Root + file;
if (serverVersion > localVersion)
{
Uri url = new Uri(sUrlToReadFileFrom);
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
response.Close();
Int64 iSize = response.ContentLength;
Int64 iRunningByteTotal = 0;
using (System.Net.WebClient client = new System.Net.WebClient())
{
using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom)))
{
using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None))
{
int iByteSize = 0;
byte[] byteBuffer = new byte[iSize];
while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
streamLocal.Write(byteBuffer, 0, iByteSize);
iRunningByteTotal += iByteSize;
double dIndex = (double)(iRunningByteTotal);
double dTotal = (double)byteBuffer.Length;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
backgroundWorker1.ReportProgress(iProgressPercentage);
}
streamLocal.Close();
}
streamRemote.Close();
}
}
//unzip
using (ZipFile zip = ZipFile.Read(file))
{
foreach (ZipEntry zipFiles in zip)
{
zipFiles.Extract(Root + "\\", true);
}
}
//download new version file
WebClient webClient = new WebClient();
webClient.DownloadFile(Server + "version.txt", #Root + "version");
//Delete Zip File
deleteFile(file);
}
}
}
My backgroundWorker1_ProgressChanged:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
label1.Text = "Downloading updates...";
}
And my backgroundWorker1_RunWorkerCompleted:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
settings_btn.Enabled = true;
start_btn_disabled.Enabled = false;
start_btn_disabled.Visible = false;
start_btn.Visible = true;
start_btn.Enabled = true;
progressBar1.Value = 100;
label1.Text = "Client is up to date!";
}
Also, a side note: I'm also having a bit problems of updating labels in backgroundWorker2_DoWork?
Any ideas?
Here's some working code which updates a label on Form1 using the BackgroundWorker.
Create a new Windows Form project and drop it in your code and it'll work.
It's super ugly, but it works.
After that, just plug your code into the DoWork method and calculate your value and send to ReportProgress.
Keep in mind that the work done in DoWork method is the actual Background Thread.
That means that in that method (DoWork) you cannot access UI (form) elements because they are on the UI thread.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button1.Enabled = true;
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
FakeCountingWork();
}
private void FakeCountingWork()
{
int totalNumber = 100;
int progressCounter = 0;
while (progressCounter < totalNumber)
{
int fakecounter = 0;
for (int x = 0; x < 100000000; x++)
{
fakecounter++;
}
progressCounter++;
backgroundWorker1.ReportProgress(progressCounter);
}
}
}
################################## EDITED TO ADD OTHER FUNCTIONALITY
Okay, here's how you can implement a label which displays the number of bytes downloaded so far.
Add a second label named label2 to your form.
Next alter the following methods from my previous example.
Here we are going to use the UserState to pass an extra value to the ProgressChanged Event. It's very simple. You can see that I'm generating a random number and it will now appear in Label2. This is where you could show your number of bytes.
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.ProgressPercentage.ToString();
label2.Text = e.UserState.ToString();
}
private void FakeCountingWork()
{
int totalNumber = 100;
int progressCounter = 0;
Random rnd = new Random();
while (progressCounter < totalNumber)
{
int fakecounter = 0;
for (int x = 0; x < 100000000; x++)
{
fakecounter++;
}
progressCounter++;
updateValue = rnd.Next();
backgroundWorker1.ReportProgress(progressCounter,updateValue);
}
}
I would imagine this is because you are trying to update UI objects on a different thread. HAve you tried using the Dispatcher if using wpf? https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke(v=vs.110).aspx
or Invoke if using Winforms? https://msdn.microsoft.com/fr-ca/library/zyzhdc6b(v=vs.85).aspx
Edit:
As #daylight pointed out to be, the UI was being updated in the progresschanged event, which executes on the thread which created the background worker, therefore there shouldn't be an issue regarding threading. See https://msdn.microsoft.com/en-us/library/ka89zff4(v=vs.110).aspx for more info
I want to do web browser bot. It should click link and wait 25 seconds.
private void webBrowserMain_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) // This is only way It worked for me.
{
if (webBrowserMain.Url.AbsoluteUri == #"http://www.clix-cents.com/pages/clickads")
{
Regex regAddId = new Regex("onclick=\\'openad\\(\"([\\d\\w]+)\"\\);", RegexOptions.IgnoreCase); // Find link and click it.
if (regAddId.IsMatch(webBrowserMain.DocumentText))
{
string AddId = regAddId.Match(webBrowserMain.DocumentText).Groups[1].ToString();
webBrowserMain.Navigate(#"http://www.clix-cents.com/pages/clickads?h=" + AddId);
}
}
else if (webBrowserMain.Url.AbsoluteUri.Contains("http://www.clix-cents.com/pages/clickads?h=")) // up to there everything is ok. But problem starts here.
{
Thread.Sleep(25000); // It pouses whole thread and browser, so timer in browser is not counting down.
Regex regCaptchaCode = new Regex("src=\\'/pages/captcha\\?t=c&s=([\\d\\w\\W]+)\\'", RegexOptions.IgnoreCase);
if (regCaptchaCode.IsMatch(webBrowserMain.DocumentText))
{
pictureBox1.ImageLocation = #"http://www.clix-cents.com/pages/captcha?t=c&s=" + regCaptchaCode.Match(webBrowserMain.DocumentText).ToString();
}
}
}
How to write bot for something like that? I have no idea.
Don't reinvent the wheel - there's already solutions out there like WatiN which is mainly used for testing but is also suitable for automation.
Code example from the WatiN page:
[Test]
public void SearchForWatiNOnGoogle()
{
using (var browser = new IE("http://www.google.com"))
{
browser.TextField(Find.ByName("q")).TypeText("WatiN");
browser.Button(Find.ByName("btnG")).Click();
Assert.IsTrue(browser.ContainsText("WatiN"));
}
}
You could probably use a timer. Eg:
private Timer t = new Timer();
private string nextUrl = "";
private void buttonStart_Click(object sender, EventArgs e)
{
t.Interval = 2500;
t.Tick += new EventHandler(t_Tick);
}
void t_Tick(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(nextUrl))
webBrowser1.Navigate(nextUrl);
else
{
Regex regCaptchaCode = new Regex("src=\\'/pages/captcha\\?t=c&s=([\\d\\w\\W]+)\\'", RegexOptions.IgnoreCase);
if (regCaptchaCode.IsMatch(webBrowserMain.DocumentText))
{
pictureBox1.ImageLocation = #"http://www.clix-cents.com/pages/captcha?t=c&s=" + regCaptchaCode.Match(webBrowserMain.DocumentText).ToString();
}
}
}
private void webBrowserMain_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) // This is only way It worked for me.
{
if (webBrowserMain.Url.AbsoluteUri == #"http://www.clix-cents.com/pages/clickads")
{
Regex regAddId = new Regex("onclick=\\'openad\\(\"([\\d\\w]+)\"\\);", RegexOptions.IgnoreCase); // Find link and click it.
if (regAddId.IsMatch(webBrowserMain.DocumentText))
{
string AddId = regAddId.Match(webBrowserMain.DocumentText).Groups[1].ToString();
nextUrl = #"http://www.clix-cents.com/pages/clickads?h=" + AddId;
t.Start();
}
}
else if (webBrowserMain.Url.AbsoluteUri.Contains("http://www.clix-cents.com/pages/clickads?h=")) // up to there everything is ok. But problem starts here.
{
nextUrl = "";
t.Start();
}
}
The actual implementation will depend on the actual data on the site and how you want to use it. If all the links are on one page and you want to open each one, you could parse for all the links and store into a list. Then start the timer. At each Tick, you could open 1 item.