Rizwan Khan
Rizwan Khan

Reputation: 401

How to use Progress bar during loading an xml File

I want to show progress bar during loading a Remote xml file. I am using Windows Application Form in 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;
        }
    }

Above code is not working for showing progressbar loading.. Please Suggest me some code. Thanks in advance

Upvotes: 4

Views: 11680

Answers (4)

rotman
rotman

Reputation: 1651

What exacly do you want to reflect by progress bar? Rather downloading the file (because it's big) or processing the file?

Progress bar reflecting processing file

Your progress bar doesn't change because your method is synchronous - nothing else will happen unit it ends. BackgroundWorker class is designed perfectly for this kind of problems. It does main work in an asynchronous manner and is able to report that progress has changed. Here is how to change tour method to use it:

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);
}

Now, the main part:

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;
}

Progress bar reflecting downloading file

Try using HttpWebRequest to get the file as a stream.

// 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;

So now you know the length of this XML file. Then you have to asynchronously read the content from stream (BackgroundWorker and StreamReader is a good idea). Use myStream.Position and myStreamLenght to calculate the progress.

I know that I'm not very specific but I just wanted to put you in the right direction. I think it doesn't make sense to write about all those things here. Here you have links that will help you dealing with Stream and BackgroundWorker:

Upvotes: 8

Scott Rippey
Scott Rippey

Reputation: 15810

The progress bar doesn't work here, because this is all "synchronous" code. The Click event blocks the UI from updating.

There are 2 solutions.

You can create a background thread to process the XML file, and the background thread reports progress to the foreground. I'd recommend using a BackgroundWorker, but there's a lot to learn before you do this.

An easier solution, although not optimal, is to refresh the form by calling Application.DoEvents() after each progress update. This should only be considered a short-term solution, because if the task isn't quick, then your application could appear to freeze.

Both solutions have a drawback - when your progress bar is refreshed, your application will also process any events. Therefore, you must manually disable your UI while the task is processing, and re-enable it when finished.

A while back, I created a reusable solution for this issue. I created a "ProgressDialog" that takes a delegate. The progress dialog executes the delegate, and captures the progress, updates its progress bar, and even calculates the time remaining. The benefit of using the ProgressDialog is that I can show the dialog in "modal" mode, which blocks the access to the main UI, and even prevents the Click event from finishing.
Unfortunately, I don't have any code to share, just the idea.

Upvotes: 2

Dracorat
Dracorat

Reputation: 1194

First it might be going too fast for you to see - try putting a Sleep in there if you're testing that, but further, the reason it's not updating is that you're processing and that happens on the same thread that the main UI is using.

You can have the program process all events by calling Application.DoEvents() but by doing so, you also reprocess anything the user might have clicked on (including this button) - so if you want to DoEvents and make sure you don't end up processing additional work, disable the form when the method starts.

All that said, a better model is to thread your work and update the progress bar on a timer or a callback.

Upvotes: 0

user1042381
user1042381

Reputation: 11

The problem is that you are using window thread, and the window can not been redrawn, until you finish button1_Click.

Use BackgroundWorker, you can report progress by calling backgroundworker.ReportProgress

Upvotes: 1

Related Questions