by
kirupa | 9 December 2007
In the
previous page, you copied some code and got the
application working just the way we wanted. In this
page, let's take a look at the code and figure out
why things worked the way they did.
As you can see, when you submit a name into the
textbox, it displays in our listbox. The code for
doing all that is only about five lines long, so let's
look at each line to figure out what exactly it did:
- ObjectDataProvider
odp
=
this.FindResource("PeopleListDS")
as
ObjectDataProvider;
In the above line, you create a new
ObjectDataProvider object, but you initialize it to the
ObjectDataProvider already defined for you in XAML.
If you recall from the previous page, we found the
line in XAML responsible for binding our listbox to
our PeopleList ObservableCollection type:
- <ObjectDataProvider
x:Key="PeopleListDS"
d:IsDataSource="True"
ObjectType="{x:Type
CollectionsDataBinding:PeopleList}"/>
The Key value is very important because it is
this value that you use to identify this particular
section of your code. In our case, our
ObjectDataProvider is keyed to the value
PeopleListDS.
To access this value in our code-behind file, you
use the FindResource
method because our ObjectDataProvider is located in
the Resources section of our Window aka
this. In other words,
you can't use FindResource on whatever you want in
the XAML. It has to be stored as a Resource, and you
need to know where the resource is stored. In our
case, this resource is stored in Window. If
you look at the surrounding XAML for the above
ObjectDataProvider declaration, you will see that it
is indeed nested inside a
Window.Resources tag.
Anyway, what gets returned by FindResource is an
object of type...object! You will need to cast it
appropriately, and that is where the
as ObjectDataProvider
text comes in. We already know that PeopleListDS is
an ObjectDataProvider, and by casting it as such, we
make that explicit.
In the end, after this line has executed, your
ObjectDataProvider object called
odp will store a
reference to the existing ObjectDataProvider being
used for the data binding between your listbox and
PeopleList.
- PeopleList
people
=
odp.Data
as
PeopleList;
The next line is fairly straighforward. Think of
your ObjectDataProvider as a wrapper for the data
used in the data binding relationship between a
target and a source. In this line, you are
essentially digging through the wrapper and getting
at the data directly using your ObjectDataProvider
odp object's Data property.
Because our ObjectDataProvider is wrapping our
PeopleList class, when you access odp's Data, you
are actually accessing the PeopleList instance used.
Just like before, I am casting the value retuned
into the type we want, which in this case is
PeopleList.
- Person
newPerson
=
new
Person();
- newPerson.PersonName
=
NameInput.Text;
Finally, something easy! In these two lines, I am
creating a new Person object and setting it's
PersonName property to the text you entered in your
textbox. The reason I am creating a new Person
object is because our PeopleList stores data in the
form of Person objects only.
- people.Add(newPerson);
In this line, I add the new person you created
earlier to the PeopleList instance we extracted from
our ObjectDataProvider. After this line executes,
your newPerson gets added to the Listbox with the
person's name displayed.
Let's spend some looking at that last line in
greater detail. Why is it that simply adding the
name to our PeopleList instance updates the listbox
accordingly? The reason is that data binding
requires a target and a source. The target is
usually a visual element, and in our case, that was
a listbox. The source is the place your data comes
from. The source in this project is the PeopleList
collection.
In order for our target to update, it needs to
first know that a change has been made to the
source. Internally, that is handled by Notify
events. Any class that implements either the
INotifyChanged or INotifyCollectionChanged
interfaces is capable of sending out change
notifications that can be heard, understood, and
acknowledged by a target.
You may be asking if our code contains any
implementations of either INotifyChanged or
INotifyCollectionChanged. The answer is yes -
indirectly via our ObservableCollection. The
ObservableCollection class is, for the most part,
just a regular Collection with
INotifyCollectionChanged implemented. This means
that, whenever an item is added or removed from our
ObservableCollection object, a change notification
is fired. Because PeopleList extends
ObservableCollection, it too inherits there
superhero powers from the ObservableCollection
class.
Ok, so you have your application working and you
saw how the code works. Beyond that, you probably
learned more than you really wanted about how your
listbox knew when to update when a new Person was
added.
Surprisingly, there is actually one more topic I
want to discuss. Part of data binding is to provide
a clean separation between visuals and logic. In the
next page, I will explain how to improve what we
have currently written to more clearly separate the
logic from the UI.
Onwards to the
next page!
|