Saturday, March 22, 2014

Part 14 Binding to Real Data at Runtime [AbsoluteBeginnersSeriesForWindowsPhone8_files]


So, how far along are we with our SoundBoard app?

Well, we have a new data model in place, and in the previous lesson we added sample
data that we used at DESIGN time to help us properly layout the app's user interface,
particularly the DataTemplate that is bound to instances of the SoundData class.

Now, IN THIS LESSON, we want to turn our attention to binding to REAL data AT RUN
TIME.

Truth be told, we could use this SAME XAML file for the "live data" at run time in our
app. If you wanted to implement it that way, you certainly could and you've already got a
head start to taking that approach ... just build out that XAML file with more instances of
SoundGroup and SoundData, then load that file at RUNTIME in the LoadData() method
of the SoundModel class.

In fact, that might be a great way to really challenge yourself ... after you finish with this
series of lessons, you could go back and re-create this app but stop at this point and
take a different data access approach. You only learn when you struggle, and an
exercise like this will force you to struggle with how to load XAML data into our data
model at runtime.

But I digress ...

Our game plan for this lesson:

1.  In the SoundModel.cs file, we'l  create a series of helper methods, each helper method designed to create instances of the SoundData class which will be added to the SoundGroup's Items collection. So we'l  create a helper method called CreateAnimalsGroup() and CreateCartoonsGroup() and so on, each one of these helper methods wil  create instances of the SoundData class and add them to the proper SoundGroup's Items col ection. 

2.  After we have all of our helper methods complete, we'l  modify the LoadData() method and call each of those helper methods. So that, when we call LoadData(), real data will be available at runtime.

1. Adding real run-time data to our app
As you can see, right now were we to run the app:


... we're not loading any data at runtime. What we want to accomplish is to set each of
the public properties of our SoundModel class, like Animals for example, to an instance
of the SoundGroup object loaded with data. So, here's an example of the interaction I
want to enable in my LoadData() method:


All that's left is to implement the CreateAnimalsGroup() helper method, like so:


1.  CreateAnimalsGroup will return an instance of SoundGroup. 

2.  We'l  create an instance of SoundGroup, which we'l  build throughout this helper method. 

3.  We'l  set the Title propertythis is what gets displayed as the Header property of the PivotItem. 

4.  Instead of typing out the full path to the audio files, we'l  save these in a variable and append it as we're initializing the FilePath property for each new instance of SoundData. 

5.  Here we add a new instance of SoundData to the Items property (a List<SoundData>) of the SoundGroup and use object initializer syntax to populate the Title and FilePath properties of each.

When we run the app:



            ... we can now see all of the actual data in the Animals PivotItem.


But wait ... where is the Animals PivotItem Title? We'll have to fix that in a moment.
Right now, let's finish adding the rest of the Create___Group() helper methods.

Here's the listing for the CreateCartoonsGroup():



Here's the listing for the CreateTauntsGroup():


Here's the listing for the CreateWarningsGroup():


And now we'll use those helper methods in our LoadData() method to populate the
associated Property of each:


2. Fixing a data binding problem with the PivotItem Header
If I attempt to run the app, I can't look at the other PivotItems to see the data because
we're missing the PivotItem Header:


My first reaction is that it's a binding issuethat the data is not being loaded correctly. I
start by looking at the OnNavigatedTo() event handler. Clearly, LoadData() is being
called here:


Next, I look at the App.xaml.cs file. In the constructor, if the viewModel is null, it will
create a new instance of the SoundModel:


I suspect that this is a timing issue. The Pivot must be requesting the App.ViewModel
when it's empty, then the DataTemplate is requesting the App.ViewModel after it has
been filled.

After staring at this for a few moments, I set breakpoints on the MainPage.xaml.cs:


Debugging the app reveals that the DataContext is being set prior to calling the
LoadData(). This means the PivotItem titles are binding right away, however the
PivotItems ItemTemplates / DataTemplates are only binding AFTER we call LoadData():


This is how we see part of the data, but not the other part. I determine that the remedy
is simplewe'll call LoadData() right after we create a new instance of the SoundModel:


    By adding the explicit call to LoadData() in the App.xaml.cs, we can re-run the app:


... and our PivotItem Titles re-appear and we can navigate to each new category to see
the data we've loaded into each. 

Recap
To recap, the big take away in this lesson is how we implemented the real data. While
there are definitely different approaches we could have taken, we chose to create
helper methods containing hard coded instances of our SoundData and SoundGroup classes in C#. We also saw how to reason our way through an odd timing issue with data binding ... debugging and understanding the order of events is a valuable skill.

Don't forget my challenge at the outset of this lesson ... I hereby challenge you to re-
create this app using a different data access technique, such as expanding the
SampleData.xaml file with real data, then loading that data at RUN TIME. Can you
figure that out? I'll bet if you spend a day working on it, you'll have it working without my
help. You might learn more from that challenge than the rest of this series because you
only truly learn when you challenge yourself.

No comments:

Post a Comment