by
kirupa | 19 November 2007
In the
previous page,
while you may not realize it right now, you took a
giant leap in making your user control more usable.
In this page, you'll see the results of the changes
you made as well as learn what exactly the changes
you made are.
At this point, you copied and pasted into your
InfoRectangle.xaml.cs file some code and hit F6 to
make sure everything was working properly. Go back
into Blend and rebuild your solution by going to
Project | Build or by pressing Ctrl + Shift + B.
In Window1.xaml,
select or insert an instance of your InfoRectangle user
control with your mouse, and take a look at the
Miscellaneous panel in your Properties pane:
[ Do you see anything interesting in your
Miscellaneous panel? ]
Notice that you now have a field called InfoText
visible. Select that field and type something
such as Hello and press Enter:
[ enter the word Hello in your
InfoText property ]
After you have pressed Enter, notice that the
text inside your user control also changed to
display what you entered in the InfoText field:
[ your InfoText user control's text has now changed
]
You can repeat that for every other InfoRectangle
user control you have displayed in your Artboard. If
you look at the XAML for your user control, you will
see that the InfoText property was set directly:
<UserControlSample:InfoRectangle ....
InfoText="New
Text!"/>
If it wasn't for what you did earlier, you could
not have set the value for your text via XAML. You
would have had to write C# code instead to directly
add your text to the appropriate InfoRectangle
instance.
The code you copied and pasted helped define a
dependency property. A dependency property is just
like a regular property, except this property is
tied deeply into the WPF property system. I will
explain more along the way, but let's first explore
the mechanics of the three parts that are needed to
create a dependency property.
The first part is the CLR wrapper that allows your
dependency property to be accessed via code:
- public
string
InfoText
- {
- get
- {
- return
(string)GetValue(InfoTextProperty);
- }
- set
- {
- SetValue(InfoTextProperty,
value);
- }
- }
In .NET, Properties allow you to easily assign and
retrieve a value using either the
get or
set keyword. In
most general cases, the property itself is
responsible for storing the
data, but in the case with dependency properties,
the data is stored deep inside the property system.
The only way to gain access to that data is by
either using GetValue
or SetValue on the
dependency property itself, and that is what we are
doing.
Now, you may be wondering why this is known as a
CRL wrapper. The main reason is that this runs only
when InfoText is called in code. When you used Blend
to set the value of the InfoText property
from the Miscellaneous panel, you didn't access this
section of code at all. It was all done via XAML as
shown as shown earlier!
That isn't to say that you can avoid this section
of code if you never plan on using C# code to set
your properties. When compiling your application,
this section of code is needed. When you actually
run your application, though, this code is bypassed
when you use XAML to set the property.
Because our InfoText property is only
called from code, you should be careful to not add
any extra code to either your
get or
set sections
unless you want that code to only run when this
property is accessed via code.
After all, any changes to our InfoText dependency
property made directly via XAML (such as what you
did in Blend) will not cause your get/set statements
to execute at all.
In this really long
line (broken into several lines for space reasons),
you actually declare and register your dependency
property:
- public
static
readonly
DependencyProperty
InfoTextProperty
=
-
DependencyProperty.Register(
-
"InfoText",
-
typeof(string),
-
typeof(InfoRectangle),
-
new
FrameworkPropertyMetadata(
new
PropertyChangedCallback(ChangeText)));
The first
thing to note is that there is a naming convention
that you must follow. Your
static field must be your dependency property's name
appended by the word
Property. That is why, in the above code, our
static field declaration is called
InfoTextProperty.
The next thing to do is register this property:
- public
static
readonly
DependencyProperty
InfoTextProperty
=
-
DependencyProperty.Register(
-
"InfoText",
-
typeof(string),
-
typeof(InfoRectangle),
-
new
FrameworkPropertyMetadata(
new
PropertyChangedCallback(ChangeText)));
Registering your property is interesting
because it really
doesn't make a lot of sense because the behind the
scenes details are hidden from view. The main thing to
remember is that, deep under the hoods, WPF has an
advanced property system that keeps track of the
various dependency properties used in an application.
There are various handshakes that you need to know
in order to access the property system, and
depending on how you shake its hand, different
results are possible.
Let's look at our DependencyProperty's
Register method in
greater detail:
- public
static
readonly
DependencyProperty
InfoTextProperty
=
-
DependencyProperty.Register(
-
"InfoText",
-
typeof(string),
-
typeof(InfoRectangle),
-
new
FrameworkPropertyMetadata(
new
PropertyChangedCallback(ChangeText)));
The first argument you pass in refers to the name
of the DependencyProperty you wish to register.
Since our DependencyProperty is called InfoText,
that is the value you enter here. If you were to
change your value to something else besides what you
named your DependencyProperty, you will find that,
while your code wont produce an error, assigning
values to your InfoText property via XAML is routed
through your CLR wrapper. There are some other (more
unwanted) side effects such as issues with applying
styles, data binding, and so on, so be sure to
specify your dependency property's name.
We covered quite a bit of ground in this page,
but there is more code explanation to do. Let's
continue digging through our code on the
next page.
Onwards to the
next page!
|