Threading and the Progress Bar

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • WhiteWizard

    Threading and the Progress Bar

    I guess it's my turn to ASK a question ;)

    Briefly my problem: I am developing a Windows app that has several User
    Controls. On one of these controls, I am copying/processing some rather
    large binary files, so have created a second thread to do the processing.
    This thread is set to be the LOWEST priority. So far so good with all that.
    HOWEVER, I am trying to provide some feedback to the user (the bane of our
    existence!) via a progress bar. I was attempting to update the progress bar
    via code in a timer's event. When I have the timer on the the same control
    as the progress bar, the application reacts the same was as it did prior to
    starting the second thread, that is, it locks up the UI until the copying is
    complete, AND the progress bar never gets updated.

    I have a Main user control that controls the activities of the other
    controls, and that has a timer on it, so I thought I would use that timer
    event instead. Same reaction. UI locks up until the copy function is
    complete, and the progress bar never gets updated.

    Any thoughts on how I can approach this? Suggestions on what I'm doing
    wrong etc?

    TIA

    WhiteWizard
    aka Gandalf
    MCSD.NET, MCAD, MCT
  • Nicholas Paldino [.NET/C# MVP]

    #2
    Re: Threading and the Progress Bar

    First, you should not be setting the priority of the thread. Generally,
    this is a bad idea. See the following blog entry for more information:



    As for updating the progress bar, why are you using a timer to indicate
    when the progress bar should be updated? Why not send notifications from
    your worker thread to the control with the progress bar?


    --
    - Nicholas Paldino [.NET/C# MVP]
    - mvp@spam.guard. caspershouse.co m

    "WhiteWizar d" <WhiteWizard@di scussions.micro soft.comwrote in message
    news:C97735B0-31D2-4EE3-9E64-DA16C01AFB18@mi crosoft.com...
    >I guess it's my turn to ASK a question ;)
    >
    Briefly my problem: I am developing a Windows app that has several User
    Controls. On one of these controls, I am copying/processing some rather
    large binary files, so have created a second thread to do the processing.
    This thread is set to be the LOWEST priority. So far so good with all
    that.
    HOWEVER, I am trying to provide some feedback to the user (the bane of our
    existence!) via a progress bar. I was attempting to update the progress
    bar
    via code in a timer's event. When I have the timer on the the same
    control
    as the progress bar, the application reacts the same was as it did prior
    to
    starting the second thread, that is, it locks up the UI until the copying
    is
    complete, AND the progress bar never gets updated.
    >
    I have a Main user control that controls the activities of the other
    controls, and that has a timer on it, so I thought I would use that timer
    event instead. Same reaction. UI locks up until the copy function is
    complete, and the progress bar never gets updated.
    >
    Any thoughts on how I can approach this? Suggestions on what I'm doing
    wrong etc?
    >
    TIA
    >
    WhiteWizard
    aka Gandalf
    MCSD.NET, MCAD, MCT

    Comment

    • WhiteWizard

      #3
      Re: Threading and the Progress Bar

      Nicholas,

      Thanks for the input, I'm going to try it without the timer.

      As for setting the thread priorities, I also generally avoid them like the
      plague, however in this case we really do need to do it.

      We are getting information from an onboard computer on the aircraft in
      "real" time (not really, but close enough for gov't work! ;). This process
      (and one other) cannot impede the processing of that data. We really don't
      care how long it takes, as long as it doesn't inhibit the main thread at all.

      Thanks for the response.

      WhiteWizard
      aka Gandalf
      MCSD.NET, MCAD, MCT


      "Nicholas Paldino [.NET/C# MVP]" wrote:
      First, you should not be setting the priority of the thread. Generally,
      this is a bad idea. See the following blog entry for more information:
      >

      >
      As for updating the progress bar, why are you using a timer to indicate
      when the progress bar should be updated? Why not send notifications from
      your worker thread to the control with the progress bar?
      >
      >
      --
      - Nicholas Paldino [.NET/C# MVP]
      - mvp@spam.guard. caspershouse.co m
      >
      "WhiteWizar d" <WhiteWizard@di scussions.micro soft.comwrote in message
      news:C97735B0-31D2-4EE3-9E64-DA16C01AFB18@mi crosoft.com...
      I guess it's my turn to ASK a question ;)

      Briefly my problem: I am developing a Windows app that has several User
      Controls. On one of these controls, I am copying/processing some rather
      large binary files, so have created a second thread to do the processing.
      This thread is set to be the LOWEST priority. So far so good with all
      that.
      HOWEVER, I am trying to provide some feedback to the user (the bane of our
      existence!) via a progress bar. I was attempting to update the progress
      bar
      via code in a timer's event. When I have the timer on the the same
      control
      as the progress bar, the application reacts the same was as it did prior
      to
      starting the second thread, that is, it locks up the UI until the copying
      is
      complete, AND the progress bar never gets updated.

      I have a Main user control that controls the activities of the other
      controls, and that has a timer on it, so I thought I would use that timer
      event instead. Same reaction. UI locks up until the copy function is
      complete, and the progress bar never gets updated.

      Any thoughts on how I can approach this? Suggestions on what I'm doing
      wrong etc?

      TIA

      WhiteWizard
      aka Gandalf
      MCSD.NET, MCAD, MCT
      >
      >
      >

      Comment

      • Stampede

        #4
        Re: Threading and the Progress Bar

        Hello,
        I'm new to GUI programming in C# and so I would like to ask this question
        here, because it's related to the topic. I had the same (or at least a very
        similar) scenario where a worker thread does some work and a progressbar
        should show the user how much of the work has already been done. But as GUI
        and threads don't really like to work together without problems, I would like
        to know how I can interact which the progressbar from the worker thread?

        greetings

        Florian

        "Nicholas Paldino [.NET/C# MVP]" wrote:
        First, you should not be setting the priority of the thread. Generally,
        this is a bad idea. See the following blog entry for more information:
        >

        >
        As for updating the progress bar, why are you using a timer to indicate
        when the progress bar should be updated? Why not send notifications from
        your worker thread to the control with the progress bar?
        >
        >
        --
        - Nicholas Paldino [.NET/C# MVP]
        - mvp@spam.guard. caspershouse.co m
        >
        "WhiteWizar d" <WhiteWizard@di scussions.micro soft.comwrote in message
        news:C97735B0-31D2-4EE3-9E64-DA16C01AFB18@mi crosoft.com...
        I guess it's my turn to ASK a question ;)

        Briefly my problem: I am developing a Windows app that has several User
        Controls. On one of these controls, I am copying/processing some rather
        large binary files, so have created a second thread to do the processing.
        This thread is set to be the LOWEST priority. So far so good with all
        that.
        HOWEVER, I am trying to provide some feedback to the user (the bane of our
        existence!) via a progress bar. I was attempting to update the progress
        bar
        via code in a timer's event. When I have the timer on the the same
        control
        as the progress bar, the application reacts the same was as it did prior
        to
        starting the second thread, that is, it locks up the UI until the copying
        is
        complete, AND the progress bar never gets updated.

        I have a Main user control that controls the activities of the other
        controls, and that has a timer on it, so I thought I would use that timer
        event instead. Same reaction. UI locks up until the copy function is
        complete, and the progress bar never gets updated.

        Any thoughts on how I can approach this? Suggestions on what I'm doing
        wrong etc?

        TIA

        WhiteWizard
        aka Gandalf
        MCSD.NET, MCAD, MCT
        >
        >
        >

        Comment

        • WhiteWizard

          #5
          Re: Threading and the Progress Bar

          Here's what I came up with, and it works just great. THANKS NICHOLAS!

          private void StartCopyThread ()
          {
          copyRMMDataThre ad = new Thread(new ThreadStart(Pro cessCopyRequest ));
          copyRMMDataThre ad.Name = "copyRMMDataThr ead";
          copyRMMDataThre ad.Priority = System.Threadin g.ThreadPriorit y.Lowest;
          copyRMMDataThre ad.Start();
          }

          private void ProcessCopyRequ est()
          {
          // some initial processing

          pbFileCopy.Valu e = 0;
          pbFileCopy.Refr esh();

          // First we create the directory on the RMM that we are going to copy the
          files to
          bool dirCreated = CreateRMMCopyDi rectories();
          if (dirCreated)
          {
          try
          {
          // If the directories were created, we create the files...

          // ...then read the trend file and process it
          string filename = strAMCDirectory + @"\trend1.bi n";
          Stream Trend = myFlightData.Re adFlightFile(fi lename);
          BinaryReader BinaryTrend = new BinaryReader(Tr end);

          while (true)
          {
          int NumberOfBytes = BinaryTrend.Rea dInt32();
          if (NumberOfBytes != 0)
          {
          byte[] binarySecond = BinaryTrend.Rea dBytes(NumberOf Bytes);
          EDSCommon.Trend DataType second = ParseBinarySeco nd(binarySecond );
          // Update the progress bar
          pbFileCopy.Valu e = Convert.ToInt32 ((Trend.Positio n / rmmTrendSize)
          * 100);
          pbFileCopy.Refr esh();

          // continue processing
          }
          }

          HTH

          WhiteWizard
          aka Gandalf
          MCSD.NET, MCAD, MCT


          "Stampede" wrote:
          Hello,
          I'm new to GUI programming in C# and so I would like to ask this question
          here, because it's related to the topic. I had the same (or at least a very
          similar) scenario where a worker thread does some work and a progressbar
          should show the user how much of the work has already been done. But as GUI
          and threads don't really like to work together without problems, I would like
          to know how I can interact which the progressbar from the worker thread?
          >
          greetings
          >
          Florian
          >
          "Nicholas Paldino [.NET/C# MVP]" wrote:
          >
          First, you should not be setting the priority of the thread. Generally,
          this is a bad idea. See the following blog entry for more information:



          As for updating the progress bar, why are you using a timer to indicate
          when the progress bar should be updated? Why not send notifications from
          your worker thread to the control with the progress bar?


          --
          - Nicholas Paldino [.NET/C# MVP]
          - mvp@spam.guard. caspershouse.co m

          "WhiteWizar d" <WhiteWizard@di scussions.micro soft.comwrote in message
          news:C97735B0-31D2-4EE3-9E64-DA16C01AFB18@mi crosoft.com...
          >I guess it's my turn to ASK a question ;)
          >
          Briefly my problem: I am developing a Windows app that has several User
          Controls. On one of these controls, I am copying/processing some rather
          large binary files, so have created a second thread to do the processing.
          This thread is set to be the LOWEST priority. So far so good with all
          that.
          HOWEVER, I am trying to provide some feedback to the user (the bane of our
          existence!) via a progress bar. I was attempting to update the progress
          bar
          via code in a timer's event. When I have the timer on the the same
          control
          as the progress bar, the application reacts the same was as it did prior
          to
          starting the second thread, that is, it locks up the UI until the copying
          is
          complete, AND the progress bar never gets updated.
          >
          I have a Main user control that controls the activities of the other
          controls, and that has a timer on it, so I thought I would use that timer
          event instead. Same reaction. UI locks up until the copy function is
          complete, and the progress bar never gets updated.
          >
          Any thoughts on how I can approach this? Suggestions on what I'm doing
          wrong etc?
          >
          TIA
          >
          WhiteWizard
          aka Gandalf
          MCSD.NET, MCAD, MCT

          Comment

          • Nicholas Paldino [.NET/C# MVP]

            #6
            Re: Threading and the Progress Bar

            Woah, you need to change this code big time.

            What I would do is before you start the new thread, set the Value
            property of your progress bar to zero.

            Then, define the following delegate:

            private delegate void SetProgressBarV alueDelegate(in t value);

            And then define the following method:

            private void SetProgressBarV alue(int value)
            {
            // Set the value.
            pbFileCopy.Valu e = value;
            }

            Then, wherever you have a call to "pbFileCopy.Val ue = ?" in your
            ProcessCopyRequ est method, change it to:

            this.Invoke(new SetProgressBarV alueDelegate(Se tProgressBarVal ue), new
            object[]{ <value});

            The reason you need to do this is that you need to make calls to update
            the UI on the UI thread. The call to Invoke takes a delegate and executes
            it on the UI thread.

            If you are using .NET 2.0, you don't even need to declare the delegate
            or the method, you could do this:

            Action<intdel = delegate(int value) { pbFileCopy.Valu e = value; };
            this.Invoke(del , new object[]{ <value});

            Hope this helps.

            --
            - Nicholas Paldino [.NET/C# MVP]
            - mvp@spam.guard. caspershouse.co m

            "WhiteWizar d" <WhiteWizard@di scussions.micro soft.comwrote in message
            news:DB695383-BD46-4BC3-BB2D-87850CC8237C@mi crosoft.com...
            Here's what I came up with, and it works just great. THANKS NICHOLAS!
            >
            private void StartCopyThread ()
            {
            copyRMMDataThre ad = new Thread(new ThreadStart(Pro cessCopyRequest ));
            copyRMMDataThre ad.Name = "copyRMMDataThr ead";
            copyRMMDataThre ad.Priority = System.Threadin g.ThreadPriorit y.Lowest;
            copyRMMDataThre ad.Start();
            }
            >
            private void ProcessCopyRequ est()
            {
            // some initial processing
            >
            pbFileCopy.Valu e = 0;
            pbFileCopy.Refr esh();
            >
            // First we create the directory on the RMM that we are going to copy the
            files to
            bool dirCreated = CreateRMMCopyDi rectories();
            if (dirCreated)
            {
            try
            {
            // If the directories were created, we create the files...
            >
            // ...then read the trend file and process it
            string filename = strAMCDirectory + @"\trend1.bi n";
            Stream Trend = myFlightData.Re adFlightFile(fi lename);
            BinaryReader BinaryTrend = new BinaryReader(Tr end);
            >
            while (true)
            {
            int NumberOfBytes = BinaryTrend.Rea dInt32();
            if (NumberOfBytes != 0)
            {
            byte[] binarySecond = BinaryTrend.Rea dBytes(NumberOf Bytes);
            EDSCommon.Trend DataType second = ParseBinarySeco nd(binarySecond );
            // Update the progress bar
            pbFileCopy.Valu e = Convert.ToInt32 ((Trend.Positio n / rmmTrendSize)
            * 100);
            pbFileCopy.Refr esh();
            >
            // continue processing
            }
            }
            >
            HTH
            >
            WhiteWizard
            aka Gandalf
            MCSD.NET, MCAD, MCT
            >
            >
            "Stampede" wrote:
            >
            >Hello,
            >I'm new to GUI programming in C# and so I would like to ask this question
            >here, because it's related to the topic. I had the same (or at least a
            >very
            >similar) scenario where a worker thread does some work and a progressbar
            >should show the user how much of the work has already been done. But as
            >GUI
            >and threads don't really like to work together without problems, I would
            >like
            >to know how I can interact which the progressbar from the worker thread?
            >>
            >greetings
            >>
            >Florian
            >>
            >"Nicholas Paldino [.NET/C# MVP]" wrote:
            >>
            First, you should not be setting the priority of the thread.
            Generally,
            this is a bad idea. See the following blog entry for more information:
            >

            >
            As for updating the progress bar, why are you using a timer to
            indicate
            when the progress bar should be updated? Why not send notifications
            from
            your worker thread to the control with the progress bar?
            >
            >
            --
            - Nicholas Paldino [.NET/C# MVP]
            - mvp@spam.guard. caspershouse.co m
            >
            "WhiteWizar d" <WhiteWizard@di scussions.micro soft.comwrote in message
            news:C97735B0-31D2-4EE3-9E64-DA16C01AFB18@mi crosoft.com...
            >I guess it's my turn to ASK a question ;)
            >
            Briefly my problem: I am developing a Windows app that has several
            User
            Controls. On one of these controls, I am copying/processing some
            rather
            large binary files, so have created a second thread to do the
            processing.
            This thread is set to be the LOWEST priority. So far so good with
            all
            that.
            HOWEVER, I am trying to provide some feedback to the user (the bane
            of our
            existence!) via a progress bar. I was attempting to update the
            progress
            bar
            via code in a timer's event. When I have the timer on the the same
            control
            as the progress bar, the application reacts the same was as it did
            prior
            to
            starting the second thread, that is, it locks up the UI until the
            copying
            is
            complete, AND the progress bar never gets updated.
            >
            I have a Main user control that controls the activities of the other
            controls, and that has a timer on it, so I thought I would use that
            timer
            event instead. Same reaction. UI locks up until the copy function
            is
            complete, and the progress bar never gets updated.
            >
            Any thoughts on how I can approach this? Suggestions on what I'm
            doing
            wrong etc?
            >
            TIA
            >
            WhiteWizard
            aka Gandalf
            MCSD.NET, MCAD, MCT
            >
            >
            >

            Comment

            • William Stacey [MVP]

              #7
              Re: Threading and the Progress Bar

              With 2.0 it can be really simple.
              private void button4_Click(o bject sender, EventArgs e)
              {
              int num = 0;
              new Thread(
              delegate()
              {
              while (num < 100)
              {
              // Do work.
              num++;
              Thread.Sleep(10 0);

              // Update progress bar.
              this.Invoke(
              (MethodInvoker) delegate()
              {
              this.progressBa r1.Value = num;
              });
              }
              }).Start();
              }

              --
              William Stacey [MVP]

              "WhiteWizar d" <WhiteWizard@di scussions.micro soft.comwrote in message
              news:C97735B0-31D2-4EE3-9E64-DA16C01AFB18@mi crosoft.com...
              |I guess it's my turn to ASK a question ;)
              |
              | Briefly my problem: I am developing a Windows app that has several User
              | Controls. On one of these controls, I am copying/processing some rather
              | large binary files, so have created a second thread to do the processing.
              | This thread is set to be the LOWEST priority. So far so good with all
              that.
              | HOWEVER, I am trying to provide some feedback to the user (the bane of our
              | existence!) via a progress bar. I was attempting to update the progress
              bar
              | via code in a timer's event. When I have the timer on the the same
              control
              | as the progress bar, the application reacts the same was as it did prior
              to
              | starting the second thread, that is, it locks up the UI until the copying
              is
              | complete, AND the progress bar never gets updated.
              |
              | I have a Main user control that controls the activities of the other
              | controls, and that has a timer on it, so I thought I would use that timer
              | event instead. Same reaction. UI locks up until the copy function is
              | complete, and the progress bar never gets updated.
              |
              | Any thoughts on how I can approach this? Suggestions on what I'm doing
              | wrong etc?
              |
              | TIA
              |
              | WhiteWizard
              | aka Gandalf
              | MCSD.NET, MCAD, MCT


              Comment

              • joachim@yamagata-europe.com

                #8
                Re: Threading and the Progress Bar

                Just a suggestion: the BackgroundWorke r class comes in very handy when
                doing resources-intensive stuff. I use it quite a lot and am very happy
                with it.
                The advantages:
                1. the load is put on a seperate thread so your GUI doesn't suffer
                the consequences
                2. you can split your code easily into a processing part and GUI
                updating parts
                This would be an example:

                private ProgressBar bar;
                private BackgroundWorke r bgWorker;

                // Initialize your progressbar
                bar = new ProgressBar();
                bar.Value = 0;
                bar.Maximum = 100;

                // Initialize your backgroundworke r
                bgWorker = new BackgroundWorke r()
                bgWorker.Worker ReportsProgress = true;
                bgWorker.DoWork += new DoWorkEventHand ler(bgWorker_Do Work);
                bgWorker.RunWor kerCompleted += new
                RunWorkerComple tedEventHandler (bgWorker_RunWo rkerCompleted);
                bgWorker.Progre ssChanged += new
                ProgressChanged EventHandler(bg Worker_Progress Changed);


                // Call to time and resources consuming code
                // asynchronously
                bgWorker.RunWor kerAsync();

                private void bgWorker_Dowork (object sender, DoWorkEventArgs e)
                {
                // Her comes your actual heavy code.
                // Keep threads separated, so no calls to GUI should be made.
                // Instead, use the ReportProgress( int myValue) method
                for (int i = 0; i < 100; i++)
                {
                bgWorker.Report Progress(i);
                }
                }

                private void bgWorker_Progre ssChanged (object sender,
                ProgressChanged EventArgs e)
                {
                // Here you can take care of the GUI
                // Update your progressbar
                bar.Value = e.ProgressPerce ntage;
                }

                private void bgWorker_RunWor kerCompleted(ob ject sender,
                RunWorkerComple tedEventArgs e)
                {
                // Here you can take care of all GUI things that need resetting
                // and stuff like that
                bar.Value = 0;
                }

                Comment

                • William Stacey [MVP]

                  #9
                  Re: Threading and the Progress Bar

                  It is fine to use. Myself I find it easier to use delegates and Invoke as
                  shown. Then I am not dealing with another class and its api, and I get a
                  more inline feel.

                  --
                  William Stacey [MVP]

                  <joachim@yamaga ta-europe.comwrote in message
                  news:1157614951 .994613.118450@ i42g2000cwa.goo glegroups.com.. .
                  | Just a suggestion: the BackgroundWorke r class comes in very handy when
                  | doing resources-intensive stuff. I use it quite a lot and am very happy
                  | with it.
                  | The advantages:
                  | 1. the load is put on a seperate thread so your GUI doesn't suffer
                  | the consequences
                  | 2. you can split your code easily into a processing part and GUI
                  | updating parts
                  | This would be an example:
                  |
                  | private ProgressBar bar;
                  | private BackgroundWorke r bgWorker;
                  |
                  | // Initialize your progressbar
                  | bar = new ProgressBar();
                  | bar.Value = 0;
                  | bar.Maximum = 100;
                  |
                  | // Initialize your backgroundworke r
                  | bgWorker = new BackgroundWorke r()
                  | bgWorker.Worker ReportsProgress = true;
                  | bgWorker.DoWork += new DoWorkEventHand ler(bgWorker_Do Work);
                  | bgWorker.RunWor kerCompleted += new
                  | RunWorkerComple tedEventHandler (bgWorker_RunWo rkerCompleted);
                  | bgWorker.Progre ssChanged += new
                  | ProgressChanged EventHandler(bg Worker_Progress Changed);
                  |
                  |
                  | // Call to time and resources consuming code
                  | // asynchronously
                  | bgWorker.RunWor kerAsync();
                  |
                  | private void bgWorker_Dowork (object sender, DoWorkEventArgs e)
                  | {
                  | // Her comes your actual heavy code.
                  | // Keep threads separated, so no calls to GUI should be made.
                  | // Instead, use the ReportProgress( int myValue) method
                  | for (int i = 0; i < 100; i++)
                  | {
                  | bgWorker.Report Progress(i);
                  | }
                  | }
                  |
                  | private void bgWorker_Progre ssChanged (object sender,
                  | ProgressChanged EventArgs e)
                  | {
                  | // Here you can take care of the GUI
                  | // Update your progressbar
                  | bar.Value = e.ProgressPerce ntage;
                  | }
                  |
                  | private void bgWorker_RunWor kerCompleted(ob ject sender,
                  | RunWorkerComple tedEventArgs e)
                  | {
                  | // Here you can take care of all GUI things that need resetting
                  | // and stuff like that
                  | bar.Value = 0;
                  | }
                  |


                  Comment

                  Working...