Sunday, November 30, 2014

XAML Data Binding Faux Pas

This post is more appropriate to a Tweet maybe, except it can't be done in 140 characters. It's just that I wasted all Saturday afternoon trying to figure out why the data binding worked on one Store App page and not another. I even started to wonder if the XAML data binding worked differently in WPF than it worked in Windows Store Apps. As it turned out, there's no difference ... I was just being an idiot and not seeing the forest for the trees! Doh!

Now, to be honest, I haven't done all that much WPF either, but I understand the MVVM concept and this is the architecture I was using for this particular Store App. Also, since I have been playing with designing cross-platform apps with Xamarin, I also had to be cognizant of that fact when designing the Shared projects for Model and ViewModel. For that reason, I was not using ObservableCollections in my Model (I forget now which platform had problems with that), but just a plain old List. My ViewModels obviously had to implement INotifyPropertyChanged, which they did, but here's where I goofed.

I had two XAML pages: a NameSearchPage and a NameDetailPage, and consequently two ViewModels: NameSearchViewModel and NameDetailViewModel. The Search stuff had been done a couple of months ago and had been working fine ... I had to put it all aside to do "real work" and I finally got back to "playing" with it over the long Thanksgiving weekend. I wanted to add the Detail page and all the plumbing for that.

So, I got it all done, but every time I chose a Name, and the Person object got passed to the Detail ViewModel when navigating to the Detail page, the Detail page would only display the limited data from the Person object that was passed in! The ViewModel was correctly hitting the server to obtain more information, and that information was correctly being filled in the Person object, but was not being updated on the Detail page. Even though I looked at everything a million times and I knew I was implementing the INotifyPropertyChanged.

What prompted me down the wrong path for troubleshooting the problem was that I couldn't figure out why, when debugging, the PropertyChanged event was always null, meaning that nothing was subscribing to the event! The data binding on the Detail page should have automatically subscribed to that event. This is why I thought that perhaps there was something subtly different between the XAML for my Search page and my Detail page and that subtle difference might cause it to work in WPF but not in a Store App. I started to create a new solution using WPF instead of Store Apps to test this hypothesis, but scrapped that as being too much work. Back to Googling ...

My mistake, probably, was doing a little too much copy/paste from the Search classes to the Detail classes. Something in the reading I did with all my Googling prompted me to check one more thing in my Detail ViewModel. Yes, I had implemented INotifyPropertyChanged:

#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged( String info)
{
    if (PropertyChanged != null)
    {
        PropertyChanged( this, new PropertyChangedEventArgs (info));
    }
}
#endregion

But, I had forgotten the most important part in the definition of my class, I forgot to actually specify INotifyPropertyChanged:

public class NameDetailViewModel : INotifyPropertyChanged

I had looked at that class so many times, and my eyes had jumped right over the missing part every time! What an idiot!! Without the INotifyPropertyChanged specified for the ViewModel, the data binding of WPF (and Store Apps, etc.) never subscribes to the PropertyChanged event, because it doesn't know that there is one!

It is all is now finally working, and I'm happy about that. Except for the part about wasting an entire Saturday afternoon!!