Как использовать индикатор выполнения при загрузке XML-файла - PullRequest
4 голосов
/ 11 ноября 2011

Я хочу показать индикатор выполнения во время загрузки удаленного XML-файла.Я использую форму заявки Windows в Visual C # 2008 Express Edition.

private void button1_Click(object sender, EventArgs e)
    {
        string text =  textBox1.Text;
        string url = "http://api.bing.net/xml.aspx?AppId=XXX&Query=" + text + "&Sources=Translation&Version=2.2&Market=en-us&Translation.SourceLanguage=en&Translation.TargetLanguage=De";

        XmlDocument xml = new XmlDocument();
        xml.Load(url);

        XmlNodeList node = xml.GetElementsByTagName("tra:TranslatedTerm");

        for (int x = 0; x < node.Count; x++ )
        {
            textBox2.Text = node[x].InnerText;
            progressbar1.Value = x;
        }
    }

Приведенный выше код не работает для отображения загрузки индикатора прогресса. Пожалуйста, предложите мне код.Заранее спасибо

Ответы [ 4 ]

9 голосов
/ 12 ноября 2011

Что именно вы хотите отразить в индикаторе выполнения? Скорее загрузка файла (потому что он большой) или обработка файла?

Индикатор выполнения, отражающий файл обработки

Ваш индикатор прогресса не меняется, потому что ваш метод синхронный - ничего не произойдет, пока он не закончится. Класс BackgroundWorker идеально подходит для такого рода задач. Он выполняет основную работу в асинхронном режиме и может сообщить, что прогресс изменился. Вот как можно изменить метод тура, чтобы использовать его:

private void button1_Click(object sender, EventArgs e)
{
    string text =  textBox1.Text;
    string url = "http://api.bing.net/xml.aspx?AppId=XXX&Query=" + text + "&Sources=Translation&Version=2.2&Market=en-us&Translation.SourceLanguage=en&Translation.TargetLanguage=De";

    XmlDocument xml = new XmlDocument();
    xml.Load(url);
    XmlNodeList node = xml.GetElementsByTagName("tra:TranslatedTerm");

    BackgroundWorker worker = new BackgroundWorker();

    // tell the background worker it can report progress
    worker.WorkerReportsProgress = true;

    // add our event handlers
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.RunWorkerCompleted);
    worker.ProgressChanged += new ProgressChangedEventHandler(this.ProgressChanged);
    worker.DoWork += new DoWorkEventHandler(this.DoWork);

    // start the worker thread
    worker.RunWorkerAsync(node);
}

Теперь основная часть:

private void DoWork(object sender, DoWorkEventArgs e)
{
   // get a reference to the worker that started this request
   BackgroundWorker workerSender = sender as BackgroundWorker;

   // get a node list from agrument passed to RunWorkerAsync
   XmlNodeList node = e.Argument as XmlNodeList;

   for (int i = 0; x < node.Count; i++)
   {
       textBox2.Text = node[i].InnerText;
       workerSender.ReportProgress(node.Count / i);
   }
}

private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // do something after work is completed     
}

public void ProgressChanged( object sender, ProgressChangedEventArgs e )
{
    progressBar.Value = e.ProgressPercentage;
}

Индикатор выполнения загрузки файла

Попробуйте использовать HttpWebRequest, чтобы получить файл в виде потока.

// Create a 'WebRequest' object with the specified url. 
WebRequest myWebRequest = WebRequest.Create(url); 

// Send the 'WebRequest' and wait for response.
WebResponse myWebResponse = myWebRequest.GetResponse(); 

// Obtain a 'Stream' object associated with the response object.
Stream myStream = myWebResponse.GetResponseStream();

long myStreamLenght = myWebResponse.ContentLength;

Итак, теперь вы знаете длину этого XML-файла. Затем вы должны асинхронно читать содержимое из потока (BackgroundWorker и StreamReader - хорошая идея). Используйте myStream.Position и myStreamLenght для расчета прогресса.

Я знаю, что я не очень конкретен, но я просто хотел направить вас в правильном направлении. Я думаю, что не имеет смысла писать обо всех этих вещах здесь. Здесь у вас есть ссылки, которые помогут вам разобраться с Stream и BackgroundWorker:

2 голосов
/ 11 ноября 2011

Индикатор выполнения здесь не работает, потому что это весь «синхронный» код.Событие Click блокирует обновление пользовательского интерфейса.

Существует 2 решения.

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

Более простое решение, хотя и не оптимальное, - обновить форму, вызывая Application.DoEvents() после каждого обновления прогресса.Это следует рассматривать только как краткосрочное решение, потому что если задача не быстрая, то ваше приложение может зависнуть.

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

Некоторое время назад я создал решение этой проблемы для повторного использования.Я создал «ProgressDialog», который принимает делегата.Диалоговое окно выполнения выполняет делегат и фиксирует прогресс, обновляет его индикатор выполнения и даже вычисляет оставшееся время.Преимущество использования ProgressDialog заключается в том, что я могу показать диалоговое окно в «модальном» режиме, который блокирует доступ к основному интерфейсу и даже предотвращает завершение события Click.
К сожалению, у меня нет никакихкод для обмена, просто идея.

1 голос
/ 11 ноября 2011

Проблема в том, что вы используете оконную нить, и окно не может быть перерисовано, пока вы не закончите button1_Click.

Используйте BackgroundWorker, вы можете сообщить о прогрессе, вызвав backgroundworker.ReportProgress

0 голосов
/ 11 ноября 2011

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

Вы можете заставить программу обрабатывать все события, вызывая Application.DoEvents (), но при этом вы также обрабатываете все, что пользователь мог щелкнуть (включая эту кнопку) - так что если вы хотите сделать DoEvents и убедиться, что вы не нажали не обрабатывать дополнительную работу, отключите форму при запуске метода.

Все вышесказанное, лучшая модель - это поточная обработка вашей работы и обновление индикатора выполнения по таймеру или обратному вызову.

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