Resolved About time Sleep.

Joined
Dec 21, 2020
Messages
14
Programming Experience
Beginner
I am working on a window form program which is going to grab info from the web repeatedly. The program is basically copy from a console program which I use
C#:
system.threading.thread.sleep(30*1000)
.
However, when it come to window form program, it make the program super slow. What I want is the data going to come out one by one, but now is the program seem to be suspended and then lot of line come out suddenly .Below is the script:
C#:
using System;
using System.Windows.Forms;
using HtmlAgilityPack;
using System.Net;
using System.IO;

namespace AAstockpriceWin
{
    public partial class Form1 : Form
    {
        private static string Currenthtml = @"http://www.aastocks.com/tc/stocks/market/bmpfutures.aspx?future=200300";
        private static string Nexthtml = @"http://www.aastocks.com/tc/stocks/market/bmpfutures.aspx?future=200301";
        public static string Html;
        public static int A=0;
        public Form1()
        {
            InitializeComponent();
        }

        private void txtFilename_TextChanged(object sender, EventArgs e)
        {

        }

        private void rd2_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void rd1_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void btnStartStop_Click(object sender, EventArgs e)
        {
            A++;
            if (rd2.Checked) { Html = Nexthtml; } else { Html = Currenthtml; }
            if (A % 2 == 0) { lbWorkornot.Text = "Stoped"; } else { lbWorkornot.Text = "Working"; }
            while (A % 2 == 1)  <<<<<<<<<<<<<<
            {               
                Info();
            }     
        }
        private void txtResult_TextChanged(object sender, EventArgs e)
        {
          
        }
        private void txtTimeinterval_TextChanged(object sender, EventArgs e)
        {
            
        }
        public void Info()
        {

            WebClient httpins = new WebClient();
            httpins.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0");
            httpins.Headers.Add("Method", "GET");

            DateTime now = DateTime.Now;
            Stream resp = httpins.OpenRead(Form1.Html);
            StreamReader resstring = new StreamReader(resp);
            string s = resstring.ReadToEnd();
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(s);
            resstring.Close();
            HtmlNode pricenode = doc.DocumentNode.SelectSingleNode("html/body/form/div[4]/div[1]/div[4]/div[5]/table/tr[1]/td[1]/div[4]");
            HtmlNode pricenow = doc.DocumentNode.SelectSingleNode("html/body/form/div[4]/div/div[4]/div[5]/table/tr[7]/td/div[5]");
            HtmlNode change = doc.DocumentNode.SelectSingleNode("/html/body/form/div[4]/div[1]/div[4]/div[5]/table/tr[1]/td[2]/div[4]/span");// html / body / form / div[4] / div[1] / div[4] / div[5] / table / tbody / tr[1] / td[2] / div[4] / span
            HtmlNode premium = doc.DocumentNode.SelectSingleNode("/html/body/form/div[4]/div[1]/div[4]/div[5]/table/tr[1]/td[3]/div[4]"); //html/body/form/div[4]/div[1]/div[4]/div[5]/table/tbody/tr[1]/td[3]/div[4]             
            txtResult.Text += $"{now.ToString("HH:mm:ss")}\tPrice: {pricenode.InnerText.Trim()}\tPremiun: {premium.InnerText.Trim().Replace("&nbsp23","")}\tChange: {change.InnerText.Trim()}\tPriceN: {pricenow.InnerText.Trim()}\r\n";
            System.Threading.Thread.Sleep(Convert.ToInt32(txtTimeinterval.Text) * 1000); <<<<<<<<<<<<<<<<<<<<
        }       
    }
}
But once the loop and the
C#:
System.Threading.Thread.Sleep(Convert.ToInt32(txtTimeinterval.Text) * 1000)
are removed it work so smooth.
What is wrong with that ?


Thank you for your attention.
 

Attachments

  • Bad.png
    Bad.png
    313 KB · Views: 20
Use a timer instead, just add one to form in designer and configure its properties, doubleclick it to generate the event handler.

The actual work to do each 30 seconds should also be done on secondary thread, see Asynchronous programming - C#
 
And reason for why your WinForms app is freezing is because you put your Sleep() call on the UI thread. The UI thread is used to keep the UI up to date. When you pause the UI thread, then all updates pause. This is why you should use a timer on the UI thread to be notified when it is time to ping the website again, and if pinging the website can take a long time, do that in another thread so that the UI thread is not stuck waiting for a response or processing the response.
 
Winforms is event driven. Events drive tasks. Where are your tasks?

That's why you don't use those events to do massive amounts of work or your UI will lockup for reasons already explained.

I can envision using a backgroundworker alone without a timer.
 
Further; do you have permission to scrape this website? I assume if it was your own, you would be using an API.

I shall just point out : AASTOCKS.com Disclaimer

The subscriber or app/website visitor agrees not to reproduce, retransmit, disseminate, distribute, broadcast, publish, circulate, sell or commercially exploit the information and contents on this app/website in any manner without the express written consent of AASTOCKS.com Limited.

This forbids what you are doing above.
 
oh god. it work so smooth right now.Thanks.
But 1 more question: Since we are now using timer, I have to wait the timer.interval time until the method actually run.
Any good idea to make it run immediately for the first time?
C#:
private void btnStartStop_Click(object sender, EventArgs e)
        {
            A++;           
            
            if (rd2.Checked) { Html = Nexthtml; } else { Html = Currenthtml; }
            if (A % 2 == 0)
            { lbWorkornot.ForeColor = System.Drawing.Color.Red;
                lbWorkornot.Text = "Stoped";
                timer1.Stop();
                timer1.Tick -= new EventHandler(Info);
            }
            else
            {lbWorkornot.ForeColor=System.Drawing.Color.Green;
                lbWorkornot.Text = "Working";
                timer1.Tick += new EventHandler(Info);
                timer1.Interval = Convert.ToInt32(txtTimeinterval.Text) * 1000;
                timer1.Start(); }                   
      
        }
where Info is the method I want to repeatedly to run.
 
Note that, if you're going to do work on a secondary thread anyway, you probably ought to use a System.Timers.Timer rather than a System.Windows.Forms.Timer. The former raises its Elapsed event on a secondary thread by default, while the latter raises its Tick event on the UI thread. That said, if you want to use a BackgroundWorker in order to be able to use its ProgressChanged and/or RunWorkerCompleted events, stick with the System.Windows.Forms.Timer.
 
Thanks for everyone. The question so far are solved. Using system.timer.timer seem cant work in different UI in this case. I simply add Info(this,null) after the start button triggered.
 
In Info you're setting txtResult.Text, you can't access UI in secondary thread. Better would be to return the result from processing in secondary thread, and in UI thread you assign the string to textbox.
Handling processing in Forms.Timer means you are doing processing in UI thread, this is strongly discouraged. Async/Await with tasks that I linked to in post 2 shows how easy it is to do this properly.
 
Back
Top Bottom