Нужно ли использовать invoke в фоновом событии progressaged Event? - PullRequest
0 голосов
/ 13 октября 2018
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Xml.Linq;
using System.Diagnostics;
using System.Management;
using System.Runtime.InteropServices;

namespace DownloadFiles
{
    public partial class Form1 : Form
    {
        Stopwatch sw = new Stopwatch();
        Stopwatch stopwatch = new Stopwatch();
        string filesdirectory = "Downloaded_Files";
        string mainurl = "http://www.usgodae.org/ftp/outgoing/fnmoc/models/navgem_0.5/latest_data/";
        List<string> parsedlinks = new List<string>();
        string path_exe = Path.GetDirectoryName(Application.LocalUserAppDataPath);

        List<string> results = new List<string>();
        //StreamWriter w = new StreamWriter(@"e:\monitordetector.txt");

        public Form1()
        {
            InitializeComponent();

            //DetectScreenName();

            label3.Text = "";
            label4.Text = "";
            label5.Text = "";
            label7.Text = "";
            button2.Enabled = false;
            button3.Enabled = false;
            filesdirectory = Path.Combine(path_exe, filesdirectory);
            if (!Directory.Exists(filesdirectory))
            {
                Directory.CreateDirectory(filesdirectory);
            }
            else
            {
                if (IsDirectoryEmpty(filesdirectory) == false)
                {
                    button3.Enabled = true;
                }
            }
        }

        public bool IsDirectoryEmpty(string path)
        {
            return !Directory.EnumerateFileSystemEntries(path).Any();
        }

        private string downloadhtml(string url)
        {
            backgroundWorker1.ReportProgress(0, "Downloading Main Url");
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Proxy = null;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader sr = new StreamReader(response.GetResponseStream());
            string html = sr.ReadToEnd();
            sr.Close();
            response.Close();
            StreamWriter w = new StreamWriter(path_exe + "\\page.html");
            w.Write(html);
            w.Close();
            return html;
        }

        int Counter = 0;
        int percentage = 0;
        int total = 0;
        int countfiletodownload = 0;
        bool processStatus = false;
        private void Parseanddownloadfiles()
        {
            downloadhtml(mainurl);
            if (bgw.CancellationPending == false)
            {
                backgroundWorker1.ReportProgress(0, "Parsing Links");
                HtmlAgilityPack.HtmlWeb hw = new HtmlAgilityPack.HtmlWeb();
                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc = hw.Load(path_exe + "\\page.html");
                foreach (HtmlAgilityPack.HtmlNode link in doc.DocumentNode.SelectNodes("//a[@href]"))
                {
                    string hrefValue = link.GetAttributeValue("href", string.Empty);
                    if (hrefValue.Contains("US"))
                    {
                        string url = "http://www.usgodae.org/ftp/outgoing/fnmoc/models/navgem_0.5/latest_data/" + hrefValue;
                        parsedlinks.Add(url);
                        if (bgw.CancellationPending == true)
                            return;
                    }
                }
                countfiletodownload = parsedlinks.Count;
                total = parsedlinks.Count;
                backgroundWorker1.ReportProgress(0, "Downloading Files");
                processStatus = true;
                for (int i = 0; i < parsedlinks.Count && bgw.CancellationPending == false; i++)
                {
                    try
                    {
                        using (WebClient client = new WebClient())
                        {
                            sw.Start();
                            Uri uri = new Uri(parsedlinks[i]);
                            string filename = parsedlinks[i].Substring(71);
                            //client.DownloadFile(parsedlinks[i], filesdirectory + "\\" + filename);
                            client.DownloadFileAsync(uri, filesdirectory + "\\" + filename);
                            Counter += 1;
                            percentage = Counter * 100 / total;
                            string filenametoreport = filename.Substring(1);
                            countfiletodownload--;
                            backgroundWorker1.ReportProgress(percentage, filenametoreport);//countfiletodownload, filenametoreport);
                        }
                    }
                    catch (Exception err)
                    {
                        string error = err.ToString();
                    }
                }
            }
        }

        /*void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            // Calculate download speed and output it to labelSpeed.
            if (label12.InvokeRequired)
            {
                label12.Invoke(new MethodInvoker(delegate
                {
                    label12.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
                }));
            }


            // Update the progressbar percentage only when the value is not the same.
            if (progressBar1.InvokeRequired)
            {
                progressBar1.Invoke(new MethodInvoker(delegate
                {
                    progressBar1.Value = e.ProgressPercentage;
                }));
            }

            // Show the percentage on our label.
            if (label13.InvokeRequired)
            {
                label13.Invoke(new MethodInvoker(delegate
                {
                    label13.Text = e.ProgressPercentage.ToString() + "%";
                }));
            }
            // Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
            if (label14.InvokeRequired)
            {
                label14.Invoke(new MethodInvoker(delegate
                {
                    label14.Text = string.Format("{0} MB's / {1} MB's",
                        (e.BytesReceived / 1024d / 1024d).ToString("0.00"),
                        (e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
                }));
            }
        }*/

        /*void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            // Reset the stopwatch.
            sw.Reset();

            if (e.Cancelled == true)
            {
                MessageBox.Show("Download has been canceled.");
            }
            else
            {
                //MessageBox.Show("Download completed!");
            }
        }*/

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        BackgroundWorker bgw;
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            bgw = (BackgroundWorker)sender;
            if (bgw.CancellationPending == true)
            {
                return;
            }
            else
            {
                Parseanddownloadfiles();
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.UserState.ToString() == "Downloading Main Url")
            {
                label3.Text = e.UserState.ToString();
            }
            if (e.UserState.ToString() == "Parsing Links")
            {
                label3.Text = e.UserState.ToString();
            }
            if (e.UserState.ToString() == "Downloading Files")
            {
                label7.Text = countfiletodownload.ToString();//parsedlinks.Count.ToString();
                label3.Text = e.UserState.ToString();
            }
            if (processStatus == true)
            {
                if (e.UserState.ToString() != "Downloading Files")
                {
                    label4.Text = e.UserState.ToString();
                    label7.Text = countfiletodownload.ToString();
                    progressBar1.Value = e.ProgressPercentage;
                    /*using (var bitmap = new Bitmap(this.Width, this.Height))
                    {
                        this.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
                        bitmap.Save(@"e:\screens\ss.gif" + countscreenshots, System.Drawing.Imaging.ImageFormat.Gif);
                        countscreenshots += 1;
                    }*/
                }
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                string fff = null;
            }
            label3.Text = "Operation Cancelled";
            button1.Enabled = true;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            label3.Text = "Cancelling Operation";
            backgroundWorker1.CancelAsync();
            button2.Enabled = false;
            timer1.Stop();
            stopwatch.Stop();
            stopwatch.Reset();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            label3.Text = "";
            label4.Text = "";
            label7.Text = "";
            backgroundWorker1.RunWorkerAsync();
            timer1.Start();
            stopwatch.Start();
            button1.Enabled = false;
            button2.Enabled = true;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Process.Start(filesdirectory);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            label5.Text = string.Format("{0:hh\\:mm\\:ss}", stopwatch.Elapsed);
        }
    }
}

по какой-то причине код внутри события делает все приложение не асинхронным.Если я комментирую код, чтобы не использовать его, то он работает нормально.

Я также хочу использовать client_DownloadProgressChanged, который сейчас не используется, для отображения и отображения информации о загрузке.

Как скоростьвремя использования информации прогрессбара для текущей загрузки файла и информации для общего прогресса загрузки.

1 Ответ

0 голосов
/ 13 октября 2018

Нет *, вам не нужно вызывать в событии BackgroundWorker's ProgressChanged.DoWork запускается в фоновом потоке, но поток, который выполняет код внутри ProgressChanged (и других обработчиков событий в фоновом редакторе), выполняется потоком, создавшим фонового рабочего процесса, который должен быть таким же, как поток, создавший другие элементы управления пользовательского интерфейса.и, следовательно, не требуется никакого вызова

* Сказав это, обратите пристальное внимание на ту часть, где я сказал, что BGW будет запускать событие ProgressChanged, используя поток, который создал BGW.В большинстве случаев это будет поток пользовательского интерфейса. Если вы использовали поток, отличный от потока пользовательского интерфейса, для создания BGW, тогда ДА, потребуется вызов.Создайте BGW в потоке пользовательского интерфейса вместе со всеми другими элементами управления, если вы хотите простой жизни.Для остальной части моего совета я предполагаю, что это то, что вы сделали.

Я не смог точно понять вашу проблему, но помните, что это поток пользовательского интерфейса, который запускает обработчик событий.Если вы отправите этот поток, выполнив какое-то длинное задание или операцию блокировки в рамках ваших усилий по обновлению меток в пользовательском интерфейсе, тогда приложение будет казаться зависшим.Вы должны позволить потоку пользовательского интерфейса завершить код в обработчике событий как можно скорее.Если ему потребуется доступ к данным из длительной или блокирующей операции, либо попросите DoWork рассчитать данные до того, как он увеличит ход, либо используйте другой метод, чтобы избежать блокировки потока пользовательского интерфейса, например шаблон асинхронной задачи

Обратите внимание, что вызывать и блокировать пользовательский интерфейс - это совершенно разные вещи.Элементы управления Windows могут быть доступны только тем потоком, с которым они были созданы.Если другой поток хочет получить доступ к элементу управления, он должен использовать Invoke, чтобы заставить поток пользовательского интерфейса выполнять эту работу.Это совсем не то, что не мешать вашему пользовательскому интерфейсу, используя поток пользовательского интерфейса для чтения 50 гигабайт с медленного сервера, и не использовать что-то, что позволяет быстро вернуться к работе по обработке оконных сообщений и поддержанию отзывчивости приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...