[SOLVED] Application.Update Not Updating Clients Opened Prior To Current Client

Answered Closed
0
0

Hello Wisej.

I am seeing some strange behaviour with data not being updated in a DataGridView for some clients. My application shows some data in a DataGridView in a window.  When data is changed by the user it is saved to the relevant model and a message is published. The window also subscribes to that message and calls Application.Update when it receives it. This means that multiple clients with that window open should see the new data. But what I am finding is that only the clients opened after the client that makes the data change will get the new data. Clients opened prior to the client that changed the data will receive the message but the data will not have changed for them and the DataGridView remains showing the out-of-date data. The next time a message arrives they will see the data they should have seen with the prior message.

I have attached a test project so you can see what is happening. If you run the test project and then open a couple of other browsers and copy and paste the URL into them you will have a few clients open. Click the ‘Open Test Window’ button on each client, remembering the order you opened the windows. If you click the ‘Change Some Data + Send Message’ button in the first client that had the window opened the data will change in the other clients (the value in the second row of the DataGridView will increase by 10). This is all OK. But if you click the ‘Change Some Data + Send Message’ button in the last browser that you opened the window in then the other browsers will not get the new data. They will receive the message (the textbox at the top of the window will have another ‘Msg’ in it) but no data changes.

Further to this, if the data is changed in one button click handler and the message is sent in a different button click handler then it all works as expected. To see this you can click the ‘Change Some Data’ button which will change the data in the DataGridView but not send a message out. If you then click the ‘Send Message’ button then all the clients will be updated regardless of whether they were opened prior to or after the window that changed the data. But if the data is changed and the message is sent from the same button event action then the clients opened prior to the one that makes the change do not get the new data.

Sorry for the longwinded description, I hope the attached example helps. I am not sure if the problem I am seeing is how I am using the Application.Update / events or if it is a system problem.

Thanks

Andrew

 

  • You must to post comments
Great Answer
0
0

Hi Andrew,

One issue is related to the framework, not exactly a bug, but it can be improved on our side.  This is what’s happening.

Your code uses a static data source, a true static shared among all sessions. When you change a field in the data source it fires a number of events that allow the data-bound controls to update their content, in this case the data grid. However, being static, the event is originated by the the thread that modified the property. When the handler is called out-of -bound (from a different thread) it doesn’t have the context (session) so the changes to the grid are not sent to the browser. You need another round of changes to update the client.

One way to solved it is to attach to the BindingComplete event and make the grid reload it’s content (dataGrid.BeingUpdate(); dataGrid.EndUpdate()). But this will cause all the cells to be reloads also when you change only one. Our data grid has a special optimization that allows it to update a single cell value (up to a threshold after which it refreshes).

A better way is to create a new BindingSource like this:

 

public class MyBindingSource : BindingSource
{
   IWisejComponent context;

  public MyBindingSource(object dataSource) : base(dataSource, null) { }

  protected override void OnListChanged(ListChangedEventArgs e) {
    if (this.context == null)
      this.context = Application.Current;

    Application.RunInContext(this.context, () => { base.OnListChanged(e); });
  }
}

This will save the current context when created, like this:

   dataGridView1.DataSource = new MyBindingSource(_listForDGV);
   dataGridView1.DataBindingComplete += DataGridView1_DataBindingComplete;

Now each grid has it’s own BindingSource with the correct context but it still uses the same shared data source.

Then in DataGridView1_DataBindingComplete you can do simply this:

private void DataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
  Application.Update(this);
}

Basically now all the grids will get the updates automatically in the correct context since they share the same data source through a BindingSource that fires the OnListChanged event in context also when being generated from another request’s thread (which can be a different session).

This will be improved internally in all data bound controls in Wisej allow using static data sources more easily.

HTH

 

 

  • Andrew Pearce
    Thanks Luca.. I’ll work through your answer and then see about using this method in my application.
  • You must to post comments
Great Answer
0
0

Hi Andrew,

I think it is just the timing of the events that causes this.  I am not with Wisej.

This seems to make it work.

private void button3_Click(object sender, EventArgs e)
{
_listForDGV[1].IntValue += 10;
Application.Update(this);
MessageService.SendMessage();
}

 

HTH – Tim

  • Andrew Pearce
    Thanks Tim. I have gone with your suggestion. Sometimes using Application.Update() and sometimes changing where I broadcast the message from gets things working for me.
  • You must to post comments
Showing 2 results