Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. .NET (Core and Framework)
  4. Crossing the UI sync context with a datasource

Crossing the UI sync context with a datasource

Scheduled Pinned Locked Moved .NET (Core and Framework)
questionwpfwcfdesignhelp
12 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JoeRip
    wrote on last edited by
    #1

    Hello - In one hand, I have a form which contains a DataGridView. Clearly, the DGV is running on the UI thread. In the other hand, I have an library object, which contains a DataTable. That datatable is updated by an internal System.Threading.Timer (not a form timer). A couple of times a second, a row is added to that table. Once I set the DataSource of the DataGridView to be the DataTable of that library object, the DGV never redraws. The data is there, it just doesn't draw. The problem is that the DataTable is being updated by a different thread than the UI thread (verified). Apparently, the "your data has changed" methods of the DGV are also being called on that other thread. So: how do I avoid this? Since the update mechanisms are private to the DataSource/Binding mechanism, there is no clear place where I can use Invoke to sync the datatable with the UI thread, so I can cross the thread boundary safely. I do own the library object. I am currently exposing the DataTable as a public object. Is there another way to get the data in the table to the DGV, in a way that crosses the thread boundary safely?

    E L J 3 Replies Last reply
    0
    • J JoeRip

      Hello - In one hand, I have a form which contains a DataGridView. Clearly, the DGV is running on the UI thread. In the other hand, I have an library object, which contains a DataTable. That datatable is updated by an internal System.Threading.Timer (not a form timer). A couple of times a second, a row is added to that table. Once I set the DataSource of the DataGridView to be the DataTable of that library object, the DGV never redraws. The data is there, it just doesn't draw. The problem is that the DataTable is being updated by a different thread than the UI thread (verified). Apparently, the "your data has changed" methods of the DGV are also being called on that other thread. So: how do I avoid this? Since the update mechanisms are private to the DataSource/Binding mechanism, there is no clear place where I can use Invoke to sync the datatable with the UI thread, so I can cross the thread boundary safely. I do own the library object. I am currently exposing the DataTable as a public object. Is there another way to get the data in the table to the DGV, in a way that crosses the thread boundary safely?

      E Offline
      E Offline
      Ed Hill _5_
      wrote on last edited by
      #2

      there may be a couple of options for you that i can think of straight away you can either Invoke the Add calls on the UI thread, or after everything has been added you can Invoke a mothod that triggers a refresh. I'm not very familiar with how this is done on winforms, but you can call invoke i believe on any control create on the UI thread. so something like

      dgv.Invoke(new Action(() =>
      {
      var toAdd = dt.NewRow();
      dt.Rows.Add(toAdd);
      }));

      This may not be the neatest way but hopefully it should be a start for you. If you need a more tailored answer to your problem pop up a code sample and i'll take a look.

      1 Reply Last reply
      0
      • J JoeRip

        Hello - In one hand, I have a form which contains a DataGridView. Clearly, the DGV is running on the UI thread. In the other hand, I have an library object, which contains a DataTable. That datatable is updated by an internal System.Threading.Timer (not a form timer). A couple of times a second, a row is added to that table. Once I set the DataSource of the DataGridView to be the DataTable of that library object, the DGV never redraws. The data is there, it just doesn't draw. The problem is that the DataTable is being updated by a different thread than the UI thread (verified). Apparently, the "your data has changed" methods of the DGV are also being called on that other thread. So: how do I avoid this? Since the update mechanisms are private to the DataSource/Binding mechanism, there is no clear place where I can use Invoke to sync the datatable with the UI thread, so I can cross the thread boundary safely. I do own the library object. I am currently exposing the DataTable as a public object. Is there another way to get the data in the table to the DGV, in a way that crosses the thread boundary safely?

        L Offline
        L Offline
        Lost User
        wrote on last edited by
        #3

        JoeRip wrote:

        So: how do I avoid this? Since the update mechanisms are private to the DataSource/Binding mechanism, there is no clear place where I can use Invoke to sync the datatable with the UI thread, so I can cross the thread boundary safely.
        I do own the library object. I am currently exposing the DataTable as a public object. Is there another way to get the data in the table to the DGV, in a way that crosses the thread boundary safely?

        MSDN has a how-to[^] on the subject. The annoying part is updating the grid if you have the new data, and this works best if the grid is in virtual mode[^].

        Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

        J 1 Reply Last reply
        0
        • J JoeRip

          Hello - In one hand, I have a form which contains a DataGridView. Clearly, the DGV is running on the UI thread. In the other hand, I have an library object, which contains a DataTable. That datatable is updated by an internal System.Threading.Timer (not a form timer). A couple of times a second, a row is added to that table. Once I set the DataSource of the DataGridView to be the DataTable of that library object, the DGV never redraws. The data is there, it just doesn't draw. The problem is that the DataTable is being updated by a different thread than the UI thread (verified). Apparently, the "your data has changed" methods of the DGV are also being called on that other thread. So: how do I avoid this? Since the update mechanisms are private to the DataSource/Binding mechanism, there is no clear place where I can use Invoke to sync the datatable with the UI thread, so I can cross the thread boundary safely. I do own the library object. I am currently exposing the DataTable as a public object. Is there another way to get the data in the table to the DGV, in a way that crosses the thread boundary safely?

          J Offline
          J Offline
          JoeRip
          wrote on last edited by
          #4

          Okay, here is a very simplified version of the problem. Note that the GrowingTable() class is normally in a separate assembly and namespace. So - I can't just convert the Timer to a FormTimer, unless I pass the form itself to the GrowingTable class, which would be incredibly ugly. And there's no clear place where I can Invoke, as there is no actual update function (that is hidden in the DataSource mechanism).

          using System;
          using System.Windows.Forms;

          namespace dgv
          {
          public partial class Form1 : Form
          {
          DataGridView dgvMain = new DataGridView();
          GrowingTable ra = new GrowingTable();

              public Form1()
              {
                  InitializeComponent();
              }
          
              private void Form1\_Load(object sender, EventArgs e)
              {
          
                  Controls.Add(dgvMain);
                  dgvMain.Dock = System.Windows.Forms.DockStyle.Fill;
                  dgvMain.Location = new System.Drawing.Point(0, 45);
                  dgvMain.DataSource = ra.itemTable;
                  ra.Start();
              }
          
              // this class would normally appear in a separate assembly and namespace
              public class GrowingTable
              {
                  public System.Data.DataTable itemTable; 
                  private System.Threading.Timer myTimer = null;
          
                  // constructor
                  public GrowingTable()
                  {
                      itemTable = new System.Data.DataTable();
                      myTimer = new System.Threading.Timer(this.AddRow, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); 
                      for (int i = 0; i < 11; i++)
                      {
                          itemTable.Columns.Add(new System.Data.DataColumn(i.ToString(), typeof(System.DateTime)));
                      }
                  }
          
                  public void Start()
                  {
                      myTimer.Change(0, 500);
                  }
          
                  private void AddRow(object state)
                  {
                      if (itemTable.Rows.Count < 50)
                      {
                          System.Data.DataRow dr = this.itemTable.NewRow();
                          for (int i = 0; i < 11; i++) { dr\[i.ToString()\] = DateTime.Now; }
                          this.itemTable.Rows.Add(dr);
                      }
                      else
                      {
                          myTimer.Dispose();
                          myTimer = null;
                      }
                  }
              }
          }
          

          }

          E 1 Reply Last reply
          0
          • L Lost User

            JoeRip wrote:

            So: how do I avoid this? Since the update mechanisms are private to the DataSource/Binding mechanism, there is no clear place where I can use Invoke to sync the datatable with the UI thread, so I can cross the thread boundary safely.
            I do own the library object. I am currently exposing the DataTable as a public object. Is there another way to get the data in the table to the DGV, in a way that crosses the thread boundary safely?

            MSDN has a how-to[^] on the subject. The annoying part is updating the grid if you have the new data, and this works best if the grid is in virtual mode[^].

            Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

            J Offline
            J Offline
            JoeRip
            wrote on last edited by
            #5

            Thanks, but those articles assume that the non-Form thread knows about the Form, and call Form methods. In my case, this library object does NOT know about the Form, and therefore cannot use Invoke to call Form methods. This is by design - the DataTable in the library object has no idea who is connecting to its DataSource, nor should it. So there is no clear place where Invoke can be used, that I can tell. On the DataGridView's side, the RowsAdded event is simply not firing, because it's on the wrong thread. So the DGV is not getting updated. I think it comes down to this: should I redesign the library object so that it takes a delegate to call after Rows.Add (seriously ugly)? Or should I not expose the DataTable directly, and look to find another method of making the DataTable's content available?

            L 1 Reply Last reply
            0
            • J JoeRip

              Thanks, but those articles assume that the non-Form thread knows about the Form, and call Form methods. In my case, this library object does NOT know about the Form, and therefore cannot use Invoke to call Form methods. This is by design - the DataTable in the library object has no idea who is connecting to its DataSource, nor should it. So there is no clear place where Invoke can be used, that I can tell. On the DataGridView's side, the RowsAdded event is simply not firing, because it's on the wrong thread. So the DGV is not getting updated. I think it comes down to this: should I redesign the library object so that it takes a delegate to call after Rows.Add (seriously ugly)? Or should I not expose the DataTable directly, and look to find another method of making the DataTable's content available?

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #6

              JoeRip wrote:

              I think it comes down to this: should I redesign the library object so that it takes a delegate to call after Rows.Add (seriously ugly)? Or should I not expose the DataTable directly, and look to find another method of making the DataTable's content available?

              Nothing "ugly" about a CallBack method; that's the way to go if you don't want to be passing a pointer to your form to the thread.

              Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

              1 Reply Last reply
              0
              • J JoeRip

                Okay, here is a very simplified version of the problem. Note that the GrowingTable() class is normally in a separate assembly and namespace. So - I can't just convert the Timer to a FormTimer, unless I pass the form itself to the GrowingTable class, which would be incredibly ugly. And there's no clear place where I can Invoke, as there is no actual update function (that is hidden in the DataSource mechanism).

                using System;
                using System.Windows.Forms;

                namespace dgv
                {
                public partial class Form1 : Form
                {
                DataGridView dgvMain = new DataGridView();
                GrowingTable ra = new GrowingTable();

                    public Form1()
                    {
                        InitializeComponent();
                    }
                
                    private void Form1\_Load(object sender, EventArgs e)
                    {
                
                        Controls.Add(dgvMain);
                        dgvMain.Dock = System.Windows.Forms.DockStyle.Fill;
                        dgvMain.Location = new System.Drawing.Point(0, 45);
                        dgvMain.DataSource = ra.itemTable;
                        ra.Start();
                    }
                
                    // this class would normally appear in a separate assembly and namespace
                    public class GrowingTable
                    {
                        public System.Data.DataTable itemTable; 
                        private System.Threading.Timer myTimer = null;
                
                        // constructor
                        public GrowingTable()
                        {
                            itemTable = new System.Data.DataTable();
                            myTimer = new System.Threading.Timer(this.AddRow, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); 
                            for (int i = 0; i < 11; i++)
                            {
                                itemTable.Columns.Add(new System.Data.DataColumn(i.ToString(), typeof(System.DateTime)));
                            }
                        }
                
                        public void Start()
                        {
                            myTimer.Change(0, 500);
                        }
                
                        private void AddRow(object state)
                        {
                            if (itemTable.Rows.Count < 50)
                            {
                                System.Data.DataRow dr = this.itemTable.NewRow();
                                for (int i = 0; i < 11; i++) { dr\[i.ToString()\] = DateTime.Now; }
                                this.itemTable.Rows.Add(dr);
                            }
                            else
                            {
                                myTimer.Dispose();
                                myTimer = null;
                            }
                        }
                    }
                }
                

                }

                E Offline
                E Offline
                Ed Hill _5_
                wrote on last edited by
                #7

                add this to Growing Table

                public Action InvokeOnUI{get;set;}

                in the AddRow method replace

                this.itemTable.Rows.Add(dr);

                with

                if (InvokeOnUI!=null)
                InvokeOnUI(()=>this.itemTable.Rows.Add(dr));
                else
                this.itemTable.Rows.Add(dr);

                and don't forget to set it up using:

                ra.InvokeOnUI = action => Invoke(action);

                the sample i made is as follows if it helps

                public partial class Form1 : Form
                {
                public Form1()
                {
                InitializeComponent();
                }
                Updater ud = new Updater();
                private void Form1_Load(object sender, EventArgs e)
                {
                this.dataGridView1.DataSource = ud.Data;

                    ud.InvokeOnIU = action => Invoke(action);
                }
                
                private void button1\_Click(object sender, EventArgs e)
                {
                    Thread run = new Thread(ud.AddInBackGround);
                    run.Start();
                }
                

                }

                public class Updater
                {
                public Updater()
                {
                Data = new DataTable();
                Data.Columns.Add("Column 1");
                Data.Columns.Add("Column 2");
                Data.Columns.Add("Column 3");
                }
                public Action InvokeOnIU { get; set; }

                public DataTable Data { get; set; }
                
                public void AddInBackGround()
                {
                    if (InvokeOnIU!=null)
                    {
                        var toAdd = Data.NewRow();
                        InvokeOnIU(()=>Data.Rows.Add(toAdd));
                    }
                }
                

                }

                L J 4 Replies Last reply
                0
                • E Ed Hill _5_

                  add this to Growing Table

                  public Action InvokeOnUI{get;set;}

                  in the AddRow method replace

                  this.itemTable.Rows.Add(dr);

                  with

                  if (InvokeOnUI!=null)
                  InvokeOnUI(()=>this.itemTable.Rows.Add(dr));
                  else
                  this.itemTable.Rows.Add(dr);

                  and don't forget to set it up using:

                  ra.InvokeOnUI = action => Invoke(action);

                  the sample i made is as follows if it helps

                  public partial class Form1 : Form
                  {
                  public Form1()
                  {
                  InitializeComponent();
                  }
                  Updater ud = new Updater();
                  private void Form1_Load(object sender, EventArgs e)
                  {
                  this.dataGridView1.DataSource = ud.Data;

                      ud.InvokeOnIU = action => Invoke(action);
                  }
                  
                  private void button1\_Click(object sender, EventArgs e)
                  {
                      Thread run = new Thread(ud.AddInBackGround);
                      run.Start();
                  }
                  

                  }

                  public class Updater
                  {
                  public Updater()
                  {
                  Data = new DataTable();
                  Data.Columns.Add("Column 1");
                  Data.Columns.Add("Column 2");
                  Data.Columns.Add("Column 3");
                  }
                  public Action InvokeOnIU { get; set; }

                  public DataTable Data { get; set; }
                  
                  public void AddInBackGround()
                  {
                      if (InvokeOnIU!=null)
                      {
                          var toAdd = Data.NewRow();
                          InvokeOnIU(()=>Data.Rows.Add(toAdd));
                      }
                  }
                  

                  }

                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #8

                  +5 for moving the dependency to a separate class, decoupling the form from the thread :thumbsup:

                  Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

                  1 Reply Last reply
                  0
                  • E Ed Hill _5_

                    add this to Growing Table

                    public Action InvokeOnUI{get;set;}

                    in the AddRow method replace

                    this.itemTable.Rows.Add(dr);

                    with

                    if (InvokeOnUI!=null)
                    InvokeOnUI(()=>this.itemTable.Rows.Add(dr));
                    else
                    this.itemTable.Rows.Add(dr);

                    and don't forget to set it up using:

                    ra.InvokeOnUI = action => Invoke(action);

                    the sample i made is as follows if it helps

                    public partial class Form1 : Form
                    {
                    public Form1()
                    {
                    InitializeComponent();
                    }
                    Updater ud = new Updater();
                    private void Form1_Load(object sender, EventArgs e)
                    {
                    this.dataGridView1.DataSource = ud.Data;

                        ud.InvokeOnIU = action => Invoke(action);
                    }
                    
                    private void button1\_Click(object sender, EventArgs e)
                    {
                        Thread run = new Thread(ud.AddInBackGround);
                        run.Start();
                    }
                    

                    }

                    public class Updater
                    {
                    public Updater()
                    {
                    Data = new DataTable();
                    Data.Columns.Add("Column 1");
                    Data.Columns.Add("Column 2");
                    Data.Columns.Add("Column 3");
                    }
                    public Action InvokeOnIU { get; set; }

                    public DataTable Data { get; set; }
                    
                    public void AddInBackGround()
                    {
                        if (InvokeOnIU!=null)
                        {
                            var toAdd = Data.NewRow();
                            InvokeOnIU(()=>Data.Rows.Add(toAdd));
                        }
                    }
                    

                    }

                    J Offline
                    J Offline
                    JoeRip
                    wrote on last edited by
                    #9

                    Thanks! Very nice. This is very similar to what I eventually settled on. Since GrowingTable() is actually in another (library) assembly completely, it can't have intimate knowledge of the UI's Form methods. And in fact, it may not be called from a Form at all. So, I simply added an optional callBack delegate parameter to GrowingTables constructor, and I let the caller pass in a callBack function, to be called on each AddRow. That way, the caller can check NeedsInvoke on his side, and invoke the callBack over to the UI thread if necessary. It's still ugly, but it's doable. I think the real solution is to not expose a DataTable directly, and handle the binding directly. Actually, looking closer at what you've done here... this might be cleaner. Will play with it tomorrow. Thanks!

                    1 Reply Last reply
                    0
                    • E Ed Hill _5_

                      add this to Growing Table

                      public Action InvokeOnUI{get;set;}

                      in the AddRow method replace

                      this.itemTable.Rows.Add(dr);

                      with

                      if (InvokeOnUI!=null)
                      InvokeOnUI(()=>this.itemTable.Rows.Add(dr));
                      else
                      this.itemTable.Rows.Add(dr);

                      and don't forget to set it up using:

                      ra.InvokeOnUI = action => Invoke(action);

                      the sample i made is as follows if it helps

                      public partial class Form1 : Form
                      {
                      public Form1()
                      {
                      InitializeComponent();
                      }
                      Updater ud = new Updater();
                      private void Form1_Load(object sender, EventArgs e)
                      {
                      this.dataGridView1.DataSource = ud.Data;

                          ud.InvokeOnIU = action => Invoke(action);
                      }
                      
                      private void button1\_Click(object sender, EventArgs e)
                      {
                          Thread run = new Thread(ud.AddInBackGround);
                          run.Start();
                      }
                      

                      }

                      public class Updater
                      {
                      public Updater()
                      {
                      Data = new DataTable();
                      Data.Columns.Add("Column 1");
                      Data.Columns.Add("Column 2");
                      Data.Columns.Add("Column 3");
                      }
                      public Action InvokeOnIU { get; set; }

                      public DataTable Data { get; set; }
                      
                      public void AddInBackGround()
                      {
                          if (InvokeOnIU!=null)
                          {
                              var toAdd = Data.NewRow();
                              InvokeOnIU(()=>Data.Rows.Add(toAdd));
                          }
                      }
                      

                      }

                      J Offline
                      J Offline
                      JoeRip
                      wrote on last edited by
                      #10

                      I think this is not general enough for what I need. GrowingTable updates its table at arbitrary times. The caller (form) can't know when to call InvokeOnIU. If I understand the code above correctly, the form is only calling InvokeOnIU when it wants to. How about this: GrowingTable will have a property, method and event:

                      bool fCallerNeedsUpdateOnItsOwnContext

                      void UpdateGTDataSource(GTUpdates updates)

                      event UpdateDataAgainstYourOwnContext

                      When GrowingTable needs to update its data, it will create a queue of updates (typically, rows to add, rows to replace other rows by id, or id's of rows to be deleted). If fCallerNeedsUpdateOnItsOwnContext is true, it will raise the UpdateDataAgainstYourOwnContext event, passing the queue of updates. Then the subscriber can call or Invoke GT.UpdateGTDataSource(updates) as it needs, to insure thread context safety. If fCallerNeedsUpdateOnItsOwnContext is false, GrowingTable will simply execute the queue of updates itself. What say you, coders?

                      E 1 Reply Last reply
                      0
                      • E Ed Hill _5_

                        add this to Growing Table

                        public Action InvokeOnUI{get;set;}

                        in the AddRow method replace

                        this.itemTable.Rows.Add(dr);

                        with

                        if (InvokeOnUI!=null)
                        InvokeOnUI(()=>this.itemTable.Rows.Add(dr));
                        else
                        this.itemTable.Rows.Add(dr);

                        and don't forget to set it up using:

                        ra.InvokeOnUI = action => Invoke(action);

                        the sample i made is as follows if it helps

                        public partial class Form1 : Form
                        {
                        public Form1()
                        {
                        InitializeComponent();
                        }
                        Updater ud = new Updater();
                        private void Form1_Load(object sender, EventArgs e)
                        {
                        this.dataGridView1.DataSource = ud.Data;

                            ud.InvokeOnIU = action => Invoke(action);
                        }
                        
                        private void button1\_Click(object sender, EventArgs e)
                        {
                            Thread run = new Thread(ud.AddInBackGround);
                            run.Start();
                        }
                        

                        }

                        public class Updater
                        {
                        public Updater()
                        {
                        Data = new DataTable();
                        Data.Columns.Add("Column 1");
                        Data.Columns.Add("Column 2");
                        Data.Columns.Add("Column 3");
                        }
                        public Action InvokeOnIU { get; set; }

                        public DataTable Data { get; set; }
                        
                        public void AddInBackGround()
                        {
                            if (InvokeOnIU!=null)
                            {
                                var toAdd = Data.NewRow();
                                InvokeOnIU(()=>Data.Rows.Add(toAdd));
                            }
                        }
                        

                        }

                        J Offline
                        J Offline
                        JoeRip
                        wrote on last edited by
                        #11

                        Well, it works. Not sure about design quality, but it was better than the hacks I was using before. Thanks for all the help! Let me know if it sucks. Here's a sample which demonstrates the pattern; first the caller/form:

                        using System;
                        using System.Windows.Forms;
                        using GrowingDataTable;

                        namespace dgv
                        {
                        public partial class Form1 : Form
                        {
                        public DataGridView dgvMain;
                        public delegate void delEventHandler(object sender,
                        GrowingDataTable.UpdateDataTableOnYourThreadContextEventArgs e);
                        public GrowingDataTable gt;

                            public Form1()
                            {
                                InitializeComponent();
                            }
                        
                            private void Form1\_Load(object sender, EventArgs e)
                            {
                                // add a datagridview to the form
                                dgvMain = new DataGridView();
                                Controls.Add(dgvMain);
                                dgvMain.Dock = System.Windows.Forms.DockStyle.Fill;
                        
                                // create the GrowingTable object
                                gt = new GrowingDataTable();
                        
                                // subscribe to the GrowingTable event
                                gt.RaiseUpdateTableAgainstYourThreadContextEvent += new 
                               EventHandler<GrowingDataTable.UpdateDataTableOnYourThreadContextEventArgs>
                              (gt\_RaiseUpdateTableAgainstYourThreadContextEvent);
                        
                                // tell gt that we want to be updated
                                gt.UpdateDataTableOnCallerThreadContext = true;
                        
                                // assign the DataTable as DataSource for our datagridview
                                dgvMain.DataSource = gt.itemTable;
                                
                                // tell the GrowingTable to start growing; 
                                // delay start for 3 seconds, add row every 1 second
                                gt.Start(3000, 1000);
                            }
                        
                            void gt\_RaiseUpdateTableAgainstYourThreadContextEvent(object sender,
                                    GrowingDataTable.UpdateDataTableOnYourThreadContextEventArgs e)
                            {
                                if (InvokeRequired) {
                                    Invoke(new
                                    delEventHandler(gt\_RaiseUpdateTableAgainstYourThreadContextEvent),
                                    new object\[\] { sender, e}); }
                                else
                                {
                                    if ((e.Updates != null) || (e.Updates.Count > 0))
                                    {
                                        gt.UpdateTableOnMyThreadContext(e.Updates);
                                    }
                                }
                            }
                        }
                        

                        }

                        Then the library class GrowingDataTable:

                        using System;
                        using System.Collections.Concurrent;

                        namespace GrowingDataTable
                        {
                        public class GrowingDataTable
                        {
                        public System.Data.DataTable item

                        1 Reply Last reply
                        0
                        • J JoeRip

                          I think this is not general enough for what I need. GrowingTable updates its table at arbitrary times. The caller (form) can't know when to call InvokeOnIU. If I understand the code above correctly, the form is only calling InvokeOnIU when it wants to. How about this: GrowingTable will have a property, method and event:

                          bool fCallerNeedsUpdateOnItsOwnContext

                          void UpdateGTDataSource(GTUpdates updates)

                          event UpdateDataAgainstYourOwnContext

                          When GrowingTable needs to update its data, it will create a queue of updates (typically, rows to add, rows to replace other rows by id, or id's of rows to be deleted). If fCallerNeedsUpdateOnItsOwnContext is true, it will raise the UpdateDataAgainstYourOwnContext event, passing the queue of updates. Then the subscriber can call or Invoke GT.UpdateGTDataSource(updates) as it needs, to insure thread context safety. If fCallerNeedsUpdateOnItsOwnContext is false, GrowingTable will simply execute the queue of updates itself. What say you, coders?

                          E Offline
                          E Offline
                          Ed Hill _5_
                          wrote on last edited by
                          #12

                          the code sample i gave you puts the class in charge of refreshing the data in total control, the one call made in the UI is just letting the GrowingTable class know how to perform tasks in sync with the UI thread. after that stage has been performed the UI has no more involvement. I'm glad you have found a solutino but the assumptin that the form is callint InvokeOnUI is not quite right.

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups