views:

805

answers:

3

Picture, if you will, a Visual Studio 2008 WPF application with a single window containing a ListBox. This application contains a method, outlined below, that binds the ListBox to the contents of a database table.

This application also happens to implement a WFC service contract, hosting said WCF service.

The data binding method below is invoked in respose to both a button press on the window, and in response to a method being remotely invoked against the WCF service hosted by the application.

When invoked by the button press the binding works correctly and the list box reflects the content of the database table. I can insert some records into the underlying table, hit the button and the contents of the list box are refreshed to reflect the new records. However, when triggered remotely via the WCF service any changes to the database are not reflected in the list box. From stepping through the code the data set contains the correct view of the table, but the list box retains the previous view of the table and doesn't reflect the contents of the data set.

Initially I thought this sounded like a threading issue, so I tried making use of Dispatcher objects but to no avail. From my investigations both calls are received on the UI thread anyway.

Any suggestions appreciated - it's probably something blindingly obvious knowing my luck...

 private void BindData()
 {
  SqlConnection connection;

  using (connection = new SqlConnection(CONNECTION_STRING))
  {
   DataSet dtSet = new DataSet();
   SqlCommand command = new SqlCommand("SELECT * FROM TheTableWithMyStuffIn", connection);
   SqlDataAdapter adapter = new SqlDataAdapter();
   connection.Open();
   adapter.SelectCommand = command;
   adapter.Fill(dtSet, "TheTableWithMyStuffIn");
   listBox1.DataContext = dtSet;
  }
 }

UPDATE: I re-implemented the remote notification mechanism to use remoting rather than WCF, and the databinding now works when invoked both remotely and locally. There must be some contextual implication of using WCF?

A: 

I'm probably totally off-beam here given that I haven't had anything to do with .NET for years, but nobody else has offered an answer so far, so here goes.

From a quick scan of the MSDN documentation on how data binding is implemented in the .NET framework, I get the impression that updates to controls are dependent upon events that are fired when properties of the bound data source change. I notice that, in the code you present, the DataContext property of the ListBox has the new DataSet assigned to it after the data has been retrieved via the Fill method.

Could it be that, with the data having already been retrieved, some event which should cause the ListBox to realise the updated data is there is happening too soon? One would assume that the setting of the DataContext property would be sufficient to cause it to update; but given that there seems to be an awful lot of plumbing behind the scenes of the framework, and that the ListBox successfully updates when modified in a different context, I would begin to suspect a leaky abstraction: that is, that although something works as expected when used in one way, it fails when used in another way, because the underlying plumbing is (although not necessarily faulty) different.

Maybe assigning the DataContext property before filling the DataSet would make the difference. Or maybe this is just a superficially reasonable guess, but totally and obviously wrong and serves only to betray my almost complete lack of knowledge of .NET's internals.

Either way, good luck :-)

NickFitz
Many thanks for the response Nick. I did try shuffling the order as you suggested, then tried various methods of recycling the DataSet, but still no luck.
Stuart Davies
A: 

I'm not sure if DataSet implements the appropriate interfaces to automagically cause a WPF list box to update, but assuming it does, try this: rather than creating a brand new DataSet and assigning it to the list box, try re-filling the same instance from the database. If I was writing this, I'd probably use an ObservableCollection<T> field rather than a DataSet but that implies that you'd need to move your data into a DTO or an entity.

Damian Powell
Cheers Dame. I have already tried recycling the data set to no effect. The bizarre thing is this works perfectly in response to the button press, it's only when called in the context of the WCF method that it doesn't work. The data will be moved into an entity model at some point - the code above is just a simplification for the purpose of illustrating the problem. It might be worth pursuing that anyway in the hope that it will fix the issue, but my inner geek needs to know why this isn't working.
Stuart Davies
+2  A: 

Hi Voodoo,

Have you tried checking out the Service Trace Viewer that comes with .Net 3/ .Net 3.5/ Windows SDK?

May be worth checking out the messages that are bouncing around, see if the anything presents itself there.

Good luck.

EDIT:

You may want to try this article on detecting silent data binding errors...

Kieron
Cheers Kieron - that article on silent data binding errors looks very interesting in the context of my problem. I have a solution working with remoting for now, but I will revisit it over the next few days with a view to getting to the bottom of why is doesn't work with WCF as the IPC mechanism.
Stuart Davies
np, keep us posted. Be interesting to see what the problem was.
Kieron
Out of a matter of interest, what type of channel are you using?
Kieron
Will deffo keep you posted - hoping to have chance to look at this again next week.I was using a basicHttpBinding with WCF, but I'm currently using a Remoting TcpChannel.
Stuart Davies