DataGridView - TextBoxColumn - background update to data source

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John J. Hughes II

    #1

    DataGridView - TextBoxColumn - background update to data source

    I have a DataGridView with a TextBoxColumn. I setting the data source to a
    List<stringvalu e in a static class. The list is filled from a background
    thread. So far all is fine and it works great, at least on my system.

    The reason I am doing this is some customers are pulling from VPN
    connections which are slow. This allows the list of rows in the data grid
    to appear a little quicker while the list which are not used as soon load in
    the background.

    Oh so with a LAN connection there is no problem since everything loads too
    quick to notice. But on the slower connections which I simulate with a
    sleep command in the list fill the data grid's text box column comes up
    empty as expected. When the list is filled the main window needs to update
    the cell to display the data.

    So to fill the cell I have tried a couple things.

    First doing a refresh on the binding that holds the data source. This works
    on drop down list but not on the data grid text boxes.

    ((CurrencyManag er)this.Binding Context[this.ratesDataG ridViewTextBoxC olumn.DataSourc e]).Refresh();

    Second replacing the data source with the same data source. This refreshes
    all the displayed cell except the selected one and when you scroll up there
    are still empty cell that may or may not in the course of time fill.

    this.ratesDataG ridViewTextBoxC olumn.DataSourc e =
    Data.clsCacheDa ta.CacheHolder. DialingProperti es;

    Third attempt was doing a refresh on the data grid itself. Looks bad
    (flicker) and does not update all the cells.

    this.DataGridVi ew1.Refresh().

    Does anyone have another suggestion?

    Regards,
    John


  • Dave Sexton

    #2
    Re: DataGridView - TextBoxColumn - background update to data source

    Hi John,

    Make sure that you are updating the data source on the UI thread only.

    If you're using the 2.0 framework use the BackgroundWorke r class to run the
    async process but don't load the data directly into the data source from
    within the DoWork event handler. Instead, save a copy of the data and make
    sure the copy is accessible to the RunWorkerComple ted event handler. The
    BackgroundWorke r class makes sure that the RunWorkerComple ted event handler is
    invoked on the UI thread, where you can update the real data source with the
    downloaded data:

    private void RunProcessAsync ()
    {
    BackgroundWorke r worker = new BackgroundWorke r();

    string asyncData = null;

    // use an anonymous method to do the async work
    worker.DoWork += delegate(object sender1, DoWorkEventArgs e1)
    {
    asyncData = "Async Data From BackgroundWorke r";
    };

    // use an anonymous method to process completion
    worker.RunWorke rCompleted += delegate(object sender2,
    RunWorkerComple tedEventArgs e2)
    {
    // update data source
    realDataSource = asyncData;
    };

    worker.RunWorke rAsync();
    }

    If you're using an early framework version then you should call Invoke on the
    Form to marshal the call to the UI thread yourself. This can be done from
    within the background thread after the download operation has completed.
    Again, you shouldn't update the real data source in the background thread, but
    save a copy of the downloaded data and update the data source from within the
    method executed by the Invoke method:

    private void RunProcessAsync ()
    {
    string asyncData = null;

    ThreadPool.Queu eUserWorkItem(n ew WaitCallback(Ru nProcess), asyncData);
    }

    private void RunProcess(obje ct state)
    {
    string asyncData = (string) state;

    asyncData = "Async Data From ThreadPool";

    // marshal a call back to the UI thread to update the data source
    Invoke(new ProcessComplete Invoker(Process Complete), asyncData);
    }

    private delegate void ProcessComplete Invoker(string asyncData);

    private void ProcessComplete (string asyncData)
    {
    // update data source
    realDataSource = asyncData;
    }

    In my examples I'm simply setting a string value to the "realDataSource "
    variable, but you can perform any operation that is required by your
    application, such as updating a DataTable or calling Refresh on a Binding.

    If this doesn't work for you then I suspect your bindings might have been
    setup incorrectly or you're not updating the appropriate data source.

    --
    Dave Sexton

    "John J. Hughes II" <no@invalid.com wrote in message
    news:%23KLSNrPB HHA.4428@TK2MSF TNGP04.phx.gbl. ..
    >I have a DataGridView with a TextBoxColumn. I setting the data source to a
    >List<stringval ue in a static class. The list is filled from a background
    >thread. So far all is fine and it works great, at least on my system.
    >
    The reason I am doing this is some customers are pulling from VPN
    connections which are slow. This allows the list of rows in the data grid
    to appear a little quicker while the list which are not used as soon load in
    the background.
    >
    Oh so with a LAN connection there is no problem since everything loads too
    quick to notice. But on the slower connections which I simulate with a
    sleep command in the list fill the data grid's text box column comes up
    empty as expected. When the list is filled the main window needs to update
    the cell to display the data.
    >
    So to fill the cell I have tried a couple things.
    >
    First doing a refresh on the binding that holds the data source. This works
    on drop down list but not on the data grid text boxes.
    >
    >
    ((CurrencyManag er)this.Binding Context[this.ratesDataG ridViewTextBoxC olumn.DataSourc e]).Refresh();
    >
    Second replacing the data source with the same data source. This refreshes
    all the displayed cell except the selected one and when you scroll up there
    are still empty cell that may or may not in the course of time fill.
    >
    this.ratesDataG ridViewTextBoxC olumn.DataSourc e =
    Data.clsCacheDa ta.CacheHolder. DialingProperti es;
    >
    Third attempt was doing a refresh on the data grid itself. Looks bad
    (flicker) and does not update all the cells.
    >
    this.DataGridVi ew1.Refresh().
    >
    Does anyone have another suggestion?
    >
    Regards,
    John
    >

    Comment

    • John J. Hughes II

      #3
      Re: DataGridView - TextBoxColumn - background update to data source

      Dave,

      Thanks for the response.

      I have the data sources set as static to the application and then being
      accessed via MDI forms, I am tying to use them as read only by the data
      grids on several forms. The static class is using the back ground worker in
      2.0 and sending a copy of the list back to the static class.

      Should I assume that this static class is not on the same thread as the MDI
      forms?

      Regards,
      John

      "Dave Sexton" <dave@jwa[remove.this]online.comwrote in message
      news:eRisLtVBHH A.3396@TK2MSFTN GP02.phx.gbl...
      Hi John,
      >
      Make sure that you are updating the data source on the UI thread only.
      >
      If you're using the 2.0 framework use the BackgroundWorke r class to run
      the async process but don't load the data directly into the data source
      from within the DoWork event handler. Instead, save a copy of the data
      and make sure the copy is accessible to the RunWorkerComple ted event
      handler. The BackgroundWorke r class makes sure that the
      RunWorkerComple ted event handler is invoked on the UI thread, where you
      can update the real data source with the downloaded data:
      >
      private void RunProcessAsync ()
      {
      BackgroundWorke r worker = new BackgroundWorke r();
      >
      string asyncData = null;
      >
      // use an anonymous method to do the async work
      worker.DoWork += delegate(object sender1, DoWorkEventArgs e1)
      {
      asyncData = "Async Data From BackgroundWorke r";
      };
      >
      // use an anonymous method to process completion
      worker.RunWorke rCompleted += delegate(object sender2,
      RunWorkerComple tedEventArgs e2)
      {
      // update data source
      realDataSource = asyncData;
      };
      >
      worker.RunWorke rAsync();
      }
      >
      If you're using an early framework version then you should call Invoke on
      the Form to marshal the call to the UI thread yourself. This can be done
      from within the background thread after the download operation has
      completed. Again, you shouldn't update the real data source in the
      background thread, but save a copy of the downloaded data and update the
      data source from within the method executed by the Invoke method:
      >
      private void RunProcessAsync ()
      {
      string asyncData = null;
      >
      ThreadPool.Queu eUserWorkItem(n ew WaitCallback(Ru nProcess), asyncData);
      }
      >
      private void RunProcess(obje ct state)
      {
      string asyncData = (string) state;
      >
      asyncData = "Async Data From ThreadPool";
      >
      // marshal a call back to the UI thread to update the data source
      Invoke(new ProcessComplete Invoker(Process Complete), asyncData);
      }
      >
      private delegate void ProcessComplete Invoker(string asyncData);
      >
      private void ProcessComplete (string asyncData)
      {
      // update data source
      realDataSource = asyncData;
      }
      >
      In my examples I'm simply setting a string value to the "realDataSource "
      variable, but you can perform any operation that is required by your
      application, such as updating a DataTable or calling Refresh on a Binding.
      >
      If this doesn't work for you then I suspect your bindings might have been
      setup incorrectly or you're not updating the appropriate data source.
      >
      --
      Dave Sexton
      >
      "John J. Hughes II" <no@invalid.com wrote in message
      news:%23KLSNrPB HHA.4428@TK2MSF TNGP04.phx.gbl. ..
      >>I have a DataGridView with a TextBoxColumn. I setting the data source to
      >>a List<stringvalu e in a static class. The list is filled from a
      >>background thread. So far all is fine and it works great, at least on my
      >>system.
      >>
      >The reason I am doing this is some customers are pulling from VPN
      >connections which are slow. This allows the list of rows in the data
      >grid to appear a little quicker while the list which are not used as soon
      >load in the background.
      >>
      >Oh so with a LAN connection there is no problem since everything loads
      >too quick to notice. But on the slower connections which I simulate
      >with a sleep command in the list fill the data grid's text box column
      >comes up empty as expected. When the list is filled the main window
      >needs to update the cell to display the data.
      >>
      >So to fill the cell I have tried a couple things.
      >>
      >First doing a refresh on the binding that holds the data source. This
      >works on drop down list but not on the data grid text boxes.
      >>
      >>
      >((CurrencyMana ger)this.Bindin gContext[this.ratesDataG ridViewTextBoxC olumn.DataSourc e]).Refresh();
      >>
      >Second replacing the data source with the same data source. This
      >refreshes all the displayed cell except the selected one and when you
      >scroll up there are still empty cell that may or may not in the course of
      >time fill.
      >>
      > this.ratesDataG ridViewTextBoxC olumn.DataSourc e =
      >Data.clsCacheD ata.CacheHolder .DialingPropert ies;
      >>
      >Third attempt was doing a refresh on the data grid itself. Looks bad
      >(flicker) and does not update all the cells.
      >>
      > this.DataGridVi ew1.Refresh().
      >>
      >Does anyone have another suggestion?
      >>
      >Regards,
      >John
      >>
      >
      >

      Comment

      • Marc Gravell

        #4
        Re: DataGridView - TextBoxColumn - background update to data source

        Well, a class is not on any specific thread without going to a lot of
        trouble... all operations (including events raised) will happen in the
        thread of the causing code - so if your background worker does something it
        will execute on the background thread, and if your UI does something it will
        execute on the UI thread. Hopefully not at the same time ;-p

        If receiving events from this class in an MDI scenario, you should check
        InvokeRequired and react accordingly. Unfortunately, data-binding may also
        attempt to hook up events, and send itself in circles in trying.

        Marc


        Comment

        • John J. Hughes II

          #5
          Re: DataGridView - TextBoxColumn - background update to data source

          Marc,

          Hum, guess I need to have two copies then, the static global copy and then a
          local copy to the form that gets invoked when changes to the static copy
          changes.

          Will try that, see if it flys.

          Regards,
          John

          "Marc Gravell" <marc.gravell@g mail.comwrote in message
          news:e6$mOfyBHH A.4808@TK2MSFTN GP03.phx.gbl...
          Well, a class is not on any specific thread without going to a lot of
          trouble... all operations (including events raised) will happen in the
          thread of the causing code - so if your background worker does something
          it will execute on the background thread, and if your UI does something it
          will execute on the UI thread. Hopefully not at the same time ;-p
          >
          If receiving events from this class in an MDI scenario, you should check
          InvokeRequired and react accordingly. Unfortunately, data-binding may also
          attempt to hook up events, and send itself in circles in trying.
          >
          Marc
          >

          Comment

          • Dave Sexton

            #6
            Re: DataGridView - TextBoxColumn - background update to data source

            Hi John,
            I have the data sources set as static to the application and then being
            accessed via MDI forms, I am tying to use them as read only by the data
            grids on several forms. The static class is using the back ground worker in
            2.0 and sending a copy of the list back to the static class.
            >
            Should I assume that this static class is not on the same thread as the MDI
            forms?
            Classes aren't on threads. Class members (instance and static) are always
            executed within a thread. Multiple threads may execute the same instance
            member or static member, simultaneously. This is where thread synchronization
            using the "lock" keyword becomes useful, for example.

            If you have bound the UI controls to your static data source then you have to
            make sure that you don't modify the data source from within your
            BackgroundWorke r.DoWork event handler because it will be running on a
            ThreadPool thread - not the UI thread.

            Unfortunately, you won't get any errors when manipulating the data source on a
            ThreadPool thread because, technically, it's a valid operation. So you'll
            have to be smarter than the controls to which the data is bound by making sure
            that you manipulate the data source from the UI thread only - the controls
            aren't going to do that for you.

            My code examples should help you with that.

            --
            Dave Sexton


            Comment

            • John J. Hughes II

              #7
              Re: DataGridView - TextBoxColumn - background update to data source

              Dave,

              My code looks very similar to your which was why I was asking if because it
              was static made a difference. The static class is created by the main
              frame and not the MDI. Oh well will review your code some more, I now have
              someplace to look if nothing else.

              Regards,
              John

              "Dave Sexton" <dave@jwa[remove.this]online.comwrote in message
              news:%23NPSGqyB HHA.4060@TK2MSF TNGP03.phx.gbl. ..
              Hi John,
              >
              >I have the data sources set as static to the application and then being
              >accessed via MDI forms, I am tying to use them as read only by the data
              >grids on several forms. The static class is using the back ground worker
              >in 2.0 and sending a copy of the list back to the static class.
              >>
              >Should I assume that this static class is not on the same thread as the
              >MDI forms?
              >
              Classes aren't on threads. Class members (instance and static) are always
              executed within a thread. Multiple threads may execute the same instance
              member or static member, simultaneously. This is where thread
              synchronization using the "lock" keyword becomes useful, for example.
              >
              If you have bound the UI controls to your static data source then you have
              to make sure that you don't modify the data source from within your
              BackgroundWorke r.DoWork event handler because it will be running on a
              ThreadPool thread - not the UI thread.
              >
              Unfortunately, you won't get any errors when manipulating the data source
              on a ThreadPool thread because, technically, it's a valid operation. So
              you'll have to be smarter than the controls to which the data is bound by
              making sure that you manipulate the data source from the UI thread only -
              the controls aren't going to do that for you.
              >
              My code examples should help you with that.
              >
              --
              Dave Sexton
              >
              >

              Comment

              • John J. Hughes II

                #8
                Re: DataGridView - TextBoxColumn - background update to data source

                Ok, the problem was I was setting the data source to an empty list and then
                trying to fill it. If I leave the data source unset and then set it when
                the list is filled the update occurs correctly.

                Thanks all for the help.

                Regards,
                John


                "John J. Hughes II" <no@invalid.com wrote in message
                news:%23KLSNrPB HHA.4428@TK2MSF TNGP04.phx.gbl. ..
                >I have a DataGridView with a TextBoxColumn. I setting the data source to
                >a List<stringvalu e in a static class. The list is filled from a
                >background thread. So far all is fine and it works great, at least on my
                >system.
                >
                The reason I am doing this is some customers are pulling from VPN
                connections which are slow. This allows the list of rows in the data grid
                to appear a little quicker while the list which are not used as soon load
                in the background.
                >
                Oh so with a LAN connection there is no problem since everything loads too
                quick to notice. But on the slower connections which I simulate with a
                sleep command in the list fill the data grid's text box column comes up
                empty as expected. When the list is filled the main window needs to
                update the cell to display the data.
                >
                So to fill the cell I have tried a couple things.
                >
                First doing a refresh on the binding that holds the data source. This
                works on drop down list but not on the data grid text boxes.
                >
                >
                ((CurrencyManag er)this.Binding Context[this.ratesDataG ridViewTextBoxC olumn.DataSourc e]).Refresh();
                >
                Second replacing the data source with the same data source. This
                refreshes all the displayed cell except the selected one and when you
                scroll up there are still empty cell that may or may not in the course of
                time fill.
                >
                this.ratesDataG ridViewTextBoxC olumn.DataSourc e =
                Data.clsCacheDa ta.CacheHolder. DialingProperti es;
                >
                Third attempt was doing a refresh on the data grid itself. Looks bad
                (flicker) and does not update all the cells.
                >
                this.DataGridVi ew1.Refresh().
                >
                Does anyone have another suggestion?
                >
                Regards,
                John
                >

                Comment

                Working...