We spent the first 9 lessons learning the absolute basics and we were able to build a
very simple app. Yes, PetSounds app is a nice start, but it's a bit limiting. Currently,
there's only one category of sounds—animal sounds—and we have two two buttons
and so, two sounds.
I want us to turn this into a more full-fledged sound board app with different categories
of sounds ... perhaps even custom sounds that we can record. We need a good way to
represent CATEGORIES of sounds in the app, and I'm willing to bet that there's at least
one template available in Visual Studio that will give us a good starting point to help get
us pretty close to what I have in mind.
So, in this lesson I want to review two project templates to learn a bit more about what
they can do and in so doing, determine if there's a fit between their built-in capabilities
and my needs for a new SoundBoard app.
Here's the game plan for this lesson:
1. Create a sample Windows Phone Databound App project template to discover it's built-in functionality and look at the code to see how it accomplished those features.
2. Repeat the process for the Windows Phone Pivot App project template.
1. Understanding the Windows Phone Databound App project template's functionality
In Visual Studio, File menu, New | Project ... opens the New Project dialog:
1. Make sure you're in the Installed | Templates | Visual C# | Windows Phone section.
2. Choose the Windows Phone Databound App project template.
3. You can leave the name as is ... we'l probably just delete this project at some point.
4. Click OK.
Once the project is created, before you do anything else, start debugging (F5). This will
allow us to observe the functionality "out of the box".
When the app runs, you see the main page containing a list of items named "runtime
one", "runtime two", etc. Each of these has a sub-title with "lorem ipsum" text:
Clicking on one of the items will reveal a second page, a details page, containing the
details of the item you clicked on. Here you see the full "lorem ipsum" associated with
the selected item:
Stop running the app and navigate to the MainPage.xaml. We want to understand how
this app works and determine if we can utilize this in our upcoming SoundBoard app.
The list of items is made possible by a control called the LongListSelector between lines 51 and 71:
Notice that it has an ItemsSource property with a binding expression (line 54). I briefly
talked about this type of binding expression in a previous lesson. We use this type of
expression to databind a list of data to a visual control. Each item in a generic list, say
for example, a List<T>, would be displayed using an ItemTemplate. You can see the
item template defined for the LongListSelector between lines 57 and 69. An
ItemTemplate property is of type DataTemplate, which is simply a data type that defines
the visual structure of a data object.
Inside the DataTemplate, we define the visual structure of each instance of data in our
collection ... a StackPanel containing two TextBlocks.
Inside each of the TextBoxes there's a Text="{Binding LineOne}" and Text="{Binding
LineTwo}" attribute value set (lines 60 and 63, respectively). That's what binds a
property of a given object to an attribute of a control. We'll see the class hierarchy for
the sample data in just a bit. First, let's look at where the data is actually coming from ...
open the SampleData folder to reveal the MainViewModelSampleData.xaml file:
If you open that file in the Solution Explorer, you'll see the XML containing the sample
data used in the app. Notice the attributes of each ItemViewModel element—LineOne
and LineTwo. They match the names of the instance properties we bind the Text
attribute to in each of the TextBoxes in our DataTemplate:
Now, let's take a look at the classes that model this data in C#. In the ViewModels
folder, there are two files:
The ItemViewModel.cs contains the class definition for the objects we're binding to.
Here again we see the LineOne and LineTwo public properties, as well as their private
field definitions and other properties that are not utilized in this sample:
I want you to be aware of something you may have not seen before ... there's some
extras added to this class definition that make it special.
1. The class implements the INotifyPropertyChanged interface.
2. As a result of that promise to implement this interface, there's a public event called PropertyChanged (and a private method called NotifyPropertyChanged) implemented.
The purpose of these additions to the class is to enable the notion of "change
management". Whenever one of the properties of this class change, if you look at the
"set" of each property (rolled up in the screen capture, above) it will call
NotifyPropertyChanged() passing in its name. The NotifyPropertyChanged method will
in turn call the PropertyChanged event. Any code that listens for that event will be
notified when the PropertyChanged() event is triggered.
To further add another clue to this story, take a look at the definition for the
MainViewModel class:
It, too ...
1. Implements INotifyPropertyChanged, and
2. the public PropertyChanged event
... however, it also has ...
3. A public ObservableCollection<ItemViewModel> called Items.
First, recall that the LongListSelector had a ItemsSource attribute set to "{Binding
Items}". Yes, that is the same "Items" here. That's what ties the collection of
ItemViewModel object instances to the list.
The Items property is of type ObservableCollection<ItemViewModel> ... as an
OBSERVABLE collection, it is aware when changes are raised from the instances it
collects, and then can report those updates to whatever is bound to it. Hopefully you
can see where we're headed with this.
The important question is: why would any other code want to be notified about changes
going on inside of this collection?
As this example stands right now, there is absolutely no reason any other code would
want to be notified because all of the sample data is "static", insomuch that it is being
loaded from a static XML file and is not expected to change while the app is running.
However, WHAT IF we wanted to support a new feature in this app where these list
items were being updated constantly from some outside source, say, a web service.
The web service delivers new "lorem ipsum" text every 30 seconds to each of the
ItemViewModel object instances? Silly as it might sound, if we added code that
dynamically changed the data in each instance of ItemViewModel every 30 seconds,
nothing else in our app would need to change. Each property that was updated would
say "Hey, my value changed!" and the entire object instance would say "Hey, I
changed!". The ObservableCollection would report this to the LongListSelector, and it
would be updated on screen magically.
So, all of this extra code ... implementing the INotifyPropertyChanged interface, the
PropertyChanged event, all of the "set" code that calls NotifyPropertyChanged() and so
on ... it's all to enable a feature called "observability", and enables an important software
development pattern called Model-View-ViewModel ... it enables controls like the
LongListSelector and others to automatically update what is displayed when the
underlying data has been updated.
Our SoundBoard app doesn't require "observability", so I'm not going to implement all
this extra code. However, if I had a good candidate for this style of application—where
my data could change often—I would definitely take the approach that has been
templated in this project.
The good news is that there's a nice template here for you—you will have to change the
class and property names, change the manner in which the data is loaded, etc., but the
pattern is nicely implemented here and can be used as a template.
The App.xaml.cs file kicks off the process of loading the data from the XML file into
instances of the data model. In the constructor, a new instance of the MainViewModel is
created and becomes available to the entire app as a property of the App class called
ViewModel:
Later in the App.xaml.cs, in the Application_Activated event (see the code comments for when this event is triggered) if the App.ViewModel's IsDataLoaded is false, then it will call the LoadData() method of the MainViewModel class. You could modify this to
retrieve data from a web service, a local database or a different XML file:
The same check is made on the MainPage.xaml.cs file's OnNavigatedTo() method. If
the data has not been loaded, load it now. Both the previous call to LoadData() and this
call exist because of how the Windows Phone OS navigates between apps with the
back button (more on that later):
Ok, so hopefully at a high level you can see how the Windows Phone Databound App
template is wired up to enable data access through a pattern called MVVM, utilizing
features in C# and the Windows Phone Runtime called "observability".
2. Understanding the Windows Phone Pivot App project template's functionality
While the Databinding project template does accommodate several features we'll want
implemented in our SoundBoard app, we still need a way to navigate between
categories of sounds. With that in mind, we'll examine the Windows Phone Pivot App
template. We'll discard our work in the previous app and File | New | Project ... to create
a new Windows Phone Pivot app:
Just as earlier in this lesson:
1. Make sure you're in the Installed | Templates | Visual C# | Windows Phone section.
2. This time, choose the Windows Phone Pivot App project template.
3. Again, you can leave the name as is ... we'l probably just delete this project at some point.
4. Click OK.
Again this time we want to immediately run the app to see what it can do without any
modifications. At first glance, the app looks identical, but notice the area below the app title:
You can swipe between views (PivotItems) by click dragging from first to second title:
Admittedly, we're working with sample data, and the LongListSelector is data bound to
the same list of objects in both cases, however, the idea is that we can create a Pivot
that has multiple PivotItem elements (what I called a view a moment ago), each
containing a LongListSelector bound to different data:
1. The Pivot is defined with two "pages", or rather, "PivotItems" ...
2. Here's the first PivotItem
3. Here's the second PivotItem
4. The content of each PivotItem mirrors the databinding example with the
LongListSelector, data models, etc.
I can see it all coming together now. We could use the Windows Phone Pivot App
template to create categories of sound icons. Each sound icon would be rendered
based on its DataTemplate. We would create a data model that would have categories
that contained collections of sounds, including information like the sound name and the
path to the wav file to be played. So the good news is that we have a clear direction for
what needs to happen next—only implementation details remain.
Recap
To recap, in this lesson we learned about the features of the Windows Phone project
templates—the Databound template and the Pivot template share almost identical
features. They both databind a LongListSelector to a data model that is populated with
data from an XML file.
Not only is the data databound to controls inside of a DataTemplate, but the templates
provide a pattern for monitoring changes to the underlying data and automatically
updating the user interface as those changes are made. We won't need that feature in
our projects, but it's nice to know there's a simple pattern we can use in these project
templates should we ever need it. Finally, we saw the use of the Pivot control to create
pivot items in our app.
No comments:
Post a Comment