A base class which implements INotifyPropertyChanged

August 29, 2007

The longer I’ve worked with WPF, the more implementations I have seen of the INotifyPropertyChanged interface.  It’s everywhere.  I have seen dozens upon dozens of classes all implement the interface separately, even though most of those classes descend directly from Object.  This blog post examines the virtues of creating a base class which implements that interface, and deriving as many classes as possible from it.

Consolidating your implementation of INotifyPropertyChanged into a base class has several benefits.

  1. You do not have to implement the same interface many times, which reduces the possibility of boredom (and programming errors…).
  2. You can easily use cached instances of PropertyChangedEventArgs, to avoid fragmenting the managed heap with semantically identical instances.
  3. You can easily use some reflection magic to verify that the property which allegedly changed actually exists (this is useful for debugging purposes, and is automatically turned off in Release builds).
  4. You can override a method to execute logic which must run after a property is set. 

I created an abstract class called BindableObject which implements INotifyPropertyChanged and provides all the goodies promised above.  At the bottom of this post you can download the source code.  Until then, let’s take a look at how it’s implemented.

Here’s the class from a high-level view:

BindableObject (class)

As you can see above, classes which descend from BindableObject can call the RaisePropertyChanged method when one of their public properties is set to a new value.  That will cause the INotifyPropertyChanged.PropertyChanged event to be raised so that the data binding system is alerted of the new value.  If a child class wants to perform some processing after a property is set, it can override the AfterPropertyChanged method.

I made the class serializable in case you need it to be.  The demo project does not make use of that aspect of the class.  Now let’s take a look at the class’s protected members:

BindableObject (protected)

Now we’ll inspect the public members of BindableObject:

 BindableObject (public)

The main point of interest here is the GetPropertyChangedEventArgs method.  It maintains a cache of PropertyChangedEventArgs instances, so that only one instance will exist for each property name passed through this class.  This caching can dramatically reduce the managed heap fragmentation caused by a property being set many times in a short period of time.  The reason I made GetPropertyChangedEventArgs public is so that any class can take advantage of its caching mechanism, even if the class does not descend from BindableObject.

In case you’re curious, here is how the property name is verified:

BindableObject (private)

If a class which descends from BindableObject passes an invalid property name into the RaisePropertyChanged method, when the property is set this helpful assertion dialog will open:

BindableObject (assertion)

Download the demo project here: BindableObject (demo project)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.


Annotating an Image in a Viewbox

August 26, 2007

In my previous blog post we reviewed a custom adorner which allowed us to place a TextBlock into the adorner layer of a Viewbox.  Putting the TextBlock in the Viewbox’s adorner layer prevented the text from being scaled by the Viewbox, so the TextBlock’s text size remained constant.  In this blog post we will take the next step forward toward providing textual annotations of an Image contained in a Viewbox.

Suppose that we need to build an application which allows the user to add short “tags,” also known as annotations, to an image.  The location of an annotation is just as important as the text it contains.  Thus our annotations must always be “anchored” above the same meaningful part of the picture, but not necessarily the same coordinate (x,y) of the Image element.  For example, consider the following three annotations and take note of how their locations help convey meaning:

 Annotating an Image in a Viewbox (large)

Now suppose that the Image element and the two big blocks of text surrounding it are in a Viewbox.  If we resize the Window all of those elements will be scaled by the Viewbox.  It is important that our annotations continue to hover above the same parts of the picture and their text remains the same size, as seen below:

 Annotating an Image in a Viewbox (medium)

If we shrink the Window even more, notice that the annotations are still at the correct meaningful locations, but certainly not at the same coordinates as before:

 Annotating an Image in a Viewbox (small)

In order to accomplish this I introduced a new class, called ViewboxAnnotation.  An instance of that class is created by the Window whenever the user clicks on the Image element, as seen below:

 Annotating an Image in a Viewbox (usage)

ViewboxAnnotation has a private constructor, which does most of that class’s heavy lifting.  That constructor is seen below:

 Annotating an Image in a Viewbox (ctor)

Halfway into that method the two private fields ‘_horizPercent’ and ‘_vertPercent’ are set.  Those fields store the percentages of the Viewbox’s width and height, respectively, by which the TextBlock in the adorner should be offset.  When the Viewbox is resized those values are used to determine the new location of the annotation text.  That logic is seen below:

 Annotating an Image in a Viewbox (helpers)

Download the demo project here: Annotating an Image in a Viewbox (demo project)   Be sure to change the file extension from .DOC to .ZIP and then decompress it.


Rendering text in the adorner layer

August 25, 2007

This blog post shows one way to render text in the adorner layer.  I created an adorner class named TextBlockAdorner, which allows you to render a TextBlock over an element by placing it into the adorner layer.  If you don’t know what the adorner layer is yet, you might want to read this article.

Christian Graus recently posted a question to the WPF Forum asking how to render text in a Viewbox, but without having the text size be affected by the scaling of the Viewbox.  The solution I came up with is shown below.

Suppose that this is the Viewbox which we want to place text over, and have that text not be scaled or modified:

TextBlockAdorner Demo (xaml)

In the code-behind for the Window which contains the Viewbox, we can use my TextBlockAdorner to specify what text to display over the Viewbox.

TextBlockAdorner Demo (usage)

After we’re done with that, the UI looks like this:

 TextBlockAdorner Demo (screenshot)

As you can see above, the text in the ViewBox is scaled down to a smaller size than the “natural” font size in the Window.  The adorner text uses the “natural” font size because it is not affected by the Viewbox.

The demo app does not provide a clean way of repositioning the adorner text, so that is an exercise left up to the reader.  There are numerous examples on the Web which show how to use a TranslateTransform to move the contents of an adorner, such as this article and my ListViewDragDropManager’s DragAdorner class.

Download the demo project here:  TextBlockAdorner Demo (demo project)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.


Prevent a binding from updating too frequently

August 20, 2007

During my WPF presentation for the NYC .NET Developer Group a few days ago, someone in the audience asked a question about the data binding system which piqued my interest.  He asked if it is possible to control how frequently a binding target is updated. 

Suppose that you have a data source where a property’s value changes very rapidly, perhaps several dozen times per second.  You would not want the UI to display all of those values because it would just look like a blur.  It would be better to govern how often the binding source’s new values are pushed to the binding target.  The question is, how can you do that in WPF?

One solution is to create a value converter which governs the data flow between source and target.  The converter can keep a time stamp which it uses to determine when the new source values can be pushed to the target.  Every time the data is pushed, the time stamp is updated so that the next push will not occur until a pre-defined duration has elapsed.

I put together a demo app which shows how to do this.  In the demo, the rapidly changing data source is called RandomNumberEngine.  It has a public property named Current, which returns a random number.  That random number changes once every millisecond.  When the value changes, the PropertyChanged event is raised so that the binding system will attempt to push that new value into a TextBlock in the UI.  The TextBlock’s Text property is bound to the Current property on the RandomNumberEngine, and that binding is where we use the UpdateThresholdConverter to govern how often the data is pushed.

Here is the XAML for the demo app’s main Window contents:

Update Threshold Converter (usage)

Here is the entire UpdateThresholdConverter class:

Update Threshold Converter (implementation)

The UpdateThreshold property represents the number of milliseconds which must elapse between successful attempts to push a new value from the binding source to target.  Returning Binding.DoNothing from the Convert method informs the binding system that no values should be updated, leaving the attempt to transfer data as a no-op.

Download the demo project here:  Update Threshold Converter (demo project)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.


The NYC .NET Developer Group presentation

August 16, 2007

I gave my WPF presentation for the NYC .NET Developer Group tonight. It went very well and the audience raised dozens of interesting questions. I was amazed to hear from Andrew Brust, one of the Developer Group’s moderators, that my presentation received a record-breaking attendance turnout; just over one hundred people! Some kind people even approached me afterwards to say that my WPF presentation was the best they’d seen, even better than some given by Microsoft folks. Thanks a lot!

For those of you who attended, I will be making the presentation material available in late September. I want to polish it up a bit and make some changes before my September presentation at VSLive! New York. If you live in the area but did not make it to the Developer Group presentation, I’ll be giving the same harangue at VSLive so stop on by.

Thanks to everyone who attended, especially those who helped make my presentation more engaging by asking questions. I had a blast and look forward to doing it again!


Animating text in WPF

August 13, 2007

One of the many treasures in WPF is the animation system.  There are many examples on the Web showing how to animate various element properties such as height, color, etc., but not many people are aware that text can be animated too.  This blog post shows how to animate text in a TextBlock.

The demo application associated with this post performs a fairly useless animation on the name of my favorite composer; Johann Sebastian Bach.  In a realistic setting you probably would not need to make Bach’s name wave up and down, and rotate in circles.  However it is conceivable that a user interface could benefit from employing the basic technique shown here.  I got the basic code sample for this demo app from Chris Anderson’s Essential Windows Presentation Foundation.

Here is what the demo application looks like:

Animating Text (screenshot 1)

Animating Text (screenshot 2)

Animating Text (screenshot 3)

It is difficult to describe exactly what these animations look like.  I recommend that you download and run the demo app at the bottom of this post to get a much clearer understanding of what the following code snippets accomplish.

Here is the XAML file for the demo app’s main Window:

Animating Text (xaml)

Two of the animation resources are marked as x:Shared=”False” because each character in the TextBlock has its own copy of them.  The “CharacterRotationPauseAnimation” is applied to the entire Timeline in which the various animations run. Since it is only used once there is no need to mark it as unshared.

Here is the method which handles the TextBlock’s Loaded event.  It configures the animations on each character in the display text.

Animating Text (StartTextAnimations)

The heart of that method is the loop which configures each character in the TextBlock’s text.  It first creates a TextEffect object for a character.  The TextEffect class allows us to apply transformations to a contiguous set of characters in a text run.  The AddTextEffectForCharacter method is seen below:

Animating Text (adding a TextEffect)

The TranslateTransform and RotateTransform objects added to the TextEffect’s Transform property are the targets of the animations.  We use a TransformGroup to associate more than one transformation with the TextEffect. 

Lastly let’s take a look at how one of the animations is configured.  The following code is used to make each character rotate in a circle, and is called from the StartTextAnimations method seen previously.

Animating Text (creating a character animation)

Download the demo project here: Animating Text (demo project)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.

[NOTE: This blog post was written while listening to Glenn Gould play Bach's keyboard partitas.]


When will WPF become a mainstream platform?

August 9, 2007

I have been involved with WPF for over a year and a half now.  I’ve seen it grow from shaky CTP builds into a great v1 platform.  Ask anyone who has worked with WPF in a non-trivial way, and you are bound to hear that it is leaps and bounds better than Windows Forms.  The platform is publicly released now and is a truly great technology, but its adoption rate is still quite low.  I’ve read numerous reports that WPF is not gaining much traction in the software world yet, and a quick search for open WPF jobs verifies it (no, I’m not looking to change jobs!). Why is WPF not being rapidly adopted?  Here are my thoughts on the issue.

Beta?  We don’t use no stinkin’ Beta!

Working with WPF currently requires you to use a beta version of Visual Studio, either VS2005 with the “Orcas” extensions or a beta build of VS2008.  Most companies don’t want their development staff building products with beta versions of Visual Studio.  Even though WPF v1 has been publicly released, the tools for working with it are still in beta.  That’s probably the biggest deterrent for most shops.  At this point, only AlphaGeeks are willing to install beta builds of VS2008 on their home machine and play with WPF in their free time.

DataGrid?  We don’t have no stinkin’ DataGrid!

WPF v1 is missing a lot of the bread and butter support for most line-of-business (LOB) apps.  The canonical example is the fact that there is no out-of-the-box DataGrid control.  Beyond that, there is no masked editor, no date/time picker, and others.  For a lot of people this is a major turnoff.  WPF v1 is just not “there yet” as a platform for developing LOB apps, many would say.

Graphic Designers?  We don’t have no stinkin’ Graphic Designers!

In my opinion, Microsoft’s marketing team pushed the “designer-developer workflow” aspect of WPF way too much.  The whole idea that WPF allows graphic designers and developers to work closely together, with XAML as the common format they share, is not that important to many software shops/IT departments.  Many shops don’t have graphic designers, so this whole aspect of WPF is completely unimportant to them.  The marketing around WPF makes the platform seem to be important for companies that create highly specialized user interfaces (i.e. Times Reader), but not standard LOB apps.  That’s an unfortunate misperception, and couldn’t be further from the truth.

Tomorrow, tomorrow, I’ll love you tomorrow.

Now that I’ve set up all the ducks in a row, let’s blow their little heads off.  :)

The obvious answer to the Beta problem is simply to wait for VS2008 to be officially released.  I predict that once VS2008 hits the market, WPF will start to gain a lot of momentum.  As shops start installing the new Visual Studio on their dev machines, and developers start exploring WPF there will be a surge of interest in the platform.  People will start considering WPF for their next app.  I think that will be the most important catalyst for WPF adoption.

The DataGrid problem has already been solved somewhat.  There are third-party WPF grid controls out there today, by companies such as Infragistics and Xceed.  In fact Infragistics has also created a masked editor, date/time picker, and other common controls that WPF does not have by default. 

I’ve heard rumors that Microsoft is going to develop a DataGridView replacement for WPF, but who knows when/if that hits the street.  The more general problem of WPF not being LOB-friendly is the main thrust behind the next release of WPF; which is part of the .NET 3.5 Framework.  Since 3.5 will be included in VS2008, the first non-beta version of Visual Studio which natively supports WPF will have all the new LOB-friendliness in it.

Lastly we have the Graphic Designer problem.  There is not much that Microsoft can do to remedy the fact that many companies don’t have such people around to make WPF apps look great.  However, I think that third-party vendors can save the day here.  Basically they have their graphic designers create eye-pleasing themes and then wrap them up in resource dictionaries which can be used by any WPF application.  Infragistics already has created what they call “ThemePacks” which allow you to do this.  I think this is a great idea!

In conclusion, I think there is still a ways to go before WPF is the de facto UI platform for most .NET shops.  Until then, I think it is wise to keep learning about WPF.  When there starts to be high demand for WPF developers it will be the people involved with the platform now who will be the highly paid experts. ;)


Handling a routed event in any class

August 6, 2007

When you handle an element’s event in XAML, the event handling method you specify must exist in the class contained in the associated code-behind file.  That’s fine for most situations, but what about when you want that element’s event(s) to be handled by another class?  In the first version of WPF there is no support for declaratively handling events with methods in arbitrary classes.  This blog post shows a way around that limitation.

I created a utility class named RoutedEventManager which exposes an attached property named HandlerInfo.  That property is of type RoutedEventHandlerInfo; a class which stores the information needed for this technique to work.  Here is an example of those classes in use.  The XAML seen below shows a Button in a Window.  The Button’s Loaded event is handled by a utility class named ButtonHelper.

RoutedEventManager (XAML)

As seen in that XAML snippet, the Button’s Loaded event is not directly assigned a handler.  The HandlerInfo attached property is set to an instance of RoutedEventHandlerInfo, specifying the information needed to eventually assign a handler to the Loaded event.  Here is the method which handles the Button’s Loaded event, in the ButtonHelper class:

RoutedEventManager (ButtonHelper)

The implementation details of ButtonHelper are unimportant, but it is worth pointing out why it handles the Button’s Loaded event.  An attached property can only be set on an element once.  In the demo app we need to handle three of the Button’s events (Click, MouseEnter, and MouseLeave), so we assign handlers to those events in the method which handles Loaded.  If you only need to handle one event “externally” on the element, say the Click event, this extra step is unnecessary.  In that case you could just establish a handler for the Click event with RoutedEventManager in XAML.

We will not delve too deep into how this works, but free feel to explore the code in the demo app at the end of this post.  For those of you with insatiable curiosity and no time to poke around in a demo project, here is the basic gist.  When the HandlerInfo attached property is set on an element, eventually this method in RoutedEventManager is invoked:

RoutedEventManager (setting new handlerinfo)

That method depends on the CreateHandler method of the RoutedEventHandlerInfo class, which is implemented like this:

RoutedEventManager (creating the event handler)

As of this writing you can only specify a static method as the event handling method.  I’m considering whether it would be helpful to be able to specify an instance method on a particular object.  If you have a compelling reason for that feature to exist, please let me know.

These classes are not “done yet.”  I’m still pondering what other functionality might be useful for them, so feel free to drop me a comment if you have a neat idea. 

Download the demo app here: RoutedEventManager (demo project)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.


Three upcoming WPF presentations

August 6, 2007

I have written about some of my upcoming WPF presentations before, but two of them are coming up soon so I wanted to publish a brief reminder.  I’ll be giving the same presentation at each of these events, perhaps with some improvements added in as time goes on.  If you’re in the area and want to hear my WPF harangue, feel free to join me!

NYC .NET Developer Group - August 16, 2007 (Thursday)

VSLive! New York 2007 – September 17, 2007 (Monday)

Boston .NET User Group – November 1, 2007 (Thursday)


Follow

Get every new post delivered to your Inbox.

Join 275 other followers