Dinner with Dr. WPF (continued)

October 30, 2008

As Walt recently mentioned here, a few WPF Disciples got together for dinner last night.  Sitting at the table was none other than Dr. WPF in the flesh.  I won’t repeat everything Walt so vividly depicted, but there are some other aspects of that experience worth noting.

I had never heard someone request a side order of XAML before; neither had the waitress.  After she told the good Doctor that they did not have XAML on the menu, he burst into hysterical laughter while threatening to “initiate a furious bout of fisticuffs.”  What can you expect from a guy who drinks kool-aid by the gallon?

After that uncomfortable episode ended, the Doc explained to us, in great detail, how man can control the movement of the Loch Ness monster through animation of TranslateTransforms and RotateTransforms.  I didn’t quite follow, but it sounded very interesting.    He lost me when he mentioned that his plan requires “one brave scuba diver to dive down to Nessy and assign the transform group to her bosom.”

When the steaks arrived, the Doc expressed discontent with the size of his meal.  He kept touching the steak with two fingers and sliding them apart.    Eventually he gave up and started to eat his meal, grumbling about some missing resource key.


Conditionally adding elements declared in XAML to the element tree

June 12, 2008

In my previous post I showed a markup extension that only creates elements declared in your XAML file if you are running with Full Trust from the CLR. After I posted that, Laurent Bugnion, a fellow WPF MVP and WPF Disciple (as well as a really great guy!), asked if I know of a way to use a markup extension to perform the moral equivalent of a #if … #elif … #endif in C#. That was an interesting question, so I decided to investigate. It turned out to be very simple.

Here is my new If class:

You can use that markup extension to conditionally add elements to the element tree, based on whether you are building a DEBUG or RELEASE build. Here is a demo of that class being used:

If you create a DEBUG build, the top TextBlock appears in the Window, otherwise the bottom TextBlock shows up. Naturally, if you have a more complicated set of build options, you can enhance my If class to take those build configurations into account.

[EDIT]

After I posted this, Andrew Smith pointed out that there is another way to achieve this, as seen here.  The approach involves the use of the Markup Compatibility XML namespace, and another assembly to contain your own XML namespaces.  That technique is more complicated to set up, but the elements in excluded blocks will not be created/seen by the XAML reader.

[/EDIT]

Download the source code here. NOTE: Change the file extension from .DOC to .ZIP and then decompress it.


WPF Podcast Player

December 19, 2007

This post shows a simple WPF application that plays podcasts.  The podcast information comes from RSS feeds.  The user has rudimentary control over a podcast, such as pausing and resuming it, adjusting the volume, and muting the podcast player.  Almost the entire application is in XAML.

In a previous post on my other blog, I showed how to create a very basic podcast player using Silverlight 2.0.  After finishing that project, I wanted to come back to WPF and build a better podcast player.  It was such a relief to return to the feature-rich world of WPF, after living a Spartan existence over in Silverlight land.

Here is what my WPF Podcast Player looks like:

WPF Podcast Player (screenshot)

As you can see, the application definitely does not provide a luxurious experience; it is pretty bare bones.  But it does offer the fundamental things need to start, pause, resume, and stop a podcast.  The only part of the application that required me to write code is pausing and resuming a podcast, since you have to call the Pause and Play methods on MediaElement.  You cannot call those methods from XAML.  In addition, a simple value converter class exists to detect if a podcast is an MP4 file, so that we do not show it (MediaElement does not seem to support that format).

All of the podcast RSS feeds are hard-coded into the ComboBox on top of the UI.  The selected item in the ComboBox is used to get the data source from which all podcasts are retrieved.  Here is how that works:

WPF Podcatcher (data sources)

Since we are binding to an RSS feed, which is an XML document, we can use XPath to pull out the values displayed in each ListBoxItem.  Here is the template used to display a podcast in the ListBox:

WPF Podcast Player (podcast template)

The remainder of the UI is just a bunch of controls which provide the user with a means of consuming and adjusting podcasts.  Here is the XAML for most of the UI:

WPF Podcast Player (controls)

Download the Visual Studio 2008 project here: WPF Podcatcher for VS2008

Download the Visual Studio 2005 project here: WPF Podcatcher for VS2005

Be sure to change the file extension from .DOC to .ZIP and then decompress the file.


LINQing WPF value converters

December 1, 2007

A new blogger in the WPF world,


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.


Customizing the selected item in a ListBox

July 30, 2007

This blog post demonstrates how to make the selected ListBoxItem in a ListBox display differently than unselected items.  We will see how to add an extra Button to the selected item, but you can add whatever you want by using the technique shown below.  This is what the demo app looks like when you run it and select an item:

Customized SelectedItem (screenshot)

The trick is to set the ListBox’s ItemTemplate to a DataTemplate which knows when to expose the extra visuals for the selected item(s).  Here’s an example of a template which knows how to do that:

 Customized SelectedItem (template)

That DataTemplate creates two Grids.  The outer Grid has two rows: the top row is for the normal item content, and the bottom row hosts the selected item’s extra content.  The inner Grid is in the bottom row.  That inner Grid has a Style which knows when to hide itself (i.e. when the ListBoxItem is not selected).

Here’s a ListBox which consumes that template:

 Customized SelectedItem (ListBox)

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


A lightweight alternative to DropShadowBitmapEffect

July 24, 2007

This blog post reviews how to create drop shadows around WPF elements in a way which does not have a noticeable impact on an application’s UI performance.

One of the biggest letdowns about the first version of WPF is the fact that bitmap effects are so terribly slow.  The most commonly used bitmap effect is the one which creates a drop shadow around an element; the DropShadowBitmapEffect.  If you start using that class to create drop shadows you will soon find your UI performance suffering immensely.  This is a shame considering how visually appealing a well-placed drop shadow can be.

Here is a screenshot which shows a ListBox with a drop shadow.  The drop shadow was created by adding a DropShadowBitmapEffect to the ListBox’s BitmapEffects collection.

Lightweight DropShadows (using DropShadowBitmapEffect)

If you were to repeatedly resize that Window, you would find that the rendering of the ListBox flickers and is slow.  Why?  The problem is that bitmap effects are not hardware accelerated, and they can execute quite often.  WPF’s support for bitmap effects requires them to be created in unmanaged code (usually C++).  There is currently no way to hardware accelerate those unmanaged routines.  I suppose it is possible to write your own bitmap effects which run themselves on a graphics card’s GPU, but that is way beyond the scope of this post!!

Fortunately there is an easy way to create drop shadows around WPF elements which does not incur any noticeable performance overhead.  The trick is to decorate an element with a SystemDropShadowChrome element.  SystemDropShadowChrome does not have nearly as many settings that you can adjust, but it provides a decent drop shadow for many situations.  Here’s a screenshot of a ListBox which is decorated with that element:

Lightweight DropShadows (usign SystemDropShadowChrome)

SystemDropShadowChrome lives in an obscure assembly and namespace.  If you want to use it, you must add a reference to one of the PresentationFramework.* assemblies (there are currently .Aero, .Luna, .Royale, and .Classic).  You will find the class in the Microsoft.Windows.Themes namespace. 

Each of the PresentationFramework.* assemblies has its own version of the SystemDropShadowChrome class, but after checking them out in Reflector I found out that they are all exactly the same.  Someone must have written the class once, and then pasted it into each of those assemblies.  So, there is no need to worry about choosing the “right” class to use at runtime, based on the user’s current operating system theme settings.  Any one of them will do.

In this post’s demo application I chose to reference the PresentationFramework.Aero assembly, as seen below:

Lightweight DropShadows (assembly references)

Once you have the assembly reference in place, you need to map the Microsoft.Windows.Themes namespace in your XAML file, like this:

xmlns:aero=”clr-namespace:Microsoft.Windows.Themes; assembly=PresentationFramework.Aero”

At that point, it’s simply a matter of wrapping an element in a SystemDropShadowChrome element, and perhaps setting its Color and/or CornerRadius properties.  Here is the XAML which does this in the demo project:

Lightweight DropShadows (XAML)

To read another perspective on the SystemDropShadowChrome class, read here.

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


Stretching Content in an Expander Header (take two)

July 18, 2007

A while ago I posted a blog entry called Stretching Content in an Expander Header which discussed a way to make the content of an Expander’s header occupy all available space in the header area.  The solution I proposed back then required the use of some code to do the trick.  Today a fellow by the name of Patrick Jones posted a comment which shows a clean solution.  His solution still requires the use of code.

After reading over his sample I realized that it is possible (and easy) to implement the functionality without writing any code at all.  The original post has been updated to show the XAML-only solution, which I like the best out of all three options (if you do not care that the header element will be clipped on the righthand side).  Here’s the relevant XAML snippet:

<Expander>
  <Expander.Header>
    <TextBlock
      Text=”I am header text…”
      Background=”Blue”
      Width=”{Binding
        RelativeSource={RelativeSource
          Mode=FindAncestor,
          AncestorType={x:Type Expander}},
        Path=ActualWidth}”

      />
  </Expander.Header>
  <TextBlock Background=”Red”>
    I am some content…
  </TextBlock>
</Expander>

NOTE: Be sure to read the original post to learn about the limitations of this XAML-only approach, and when it is necessary to use the original technique.


Displaying sorted enum values in a ComboBox

June 20, 2007

Recently Karl Shifflett, a budding WPF developer and author of articles about WPF, posted an article on CodeProject.  The article demonstrates how to bind a ComboBox to a sorted collection of enum values.  His approach aims to be XAML-only, and it came pretty close.  After reading his article I realized that it is possible to take it one final step further toward being purely XAML.

His technique involves using an ObjectDataProvider to call a method in the code-behind which returns a sorted collection of enum values.  The method in the code-behind is responsible for sorting the enum values.  His approach is perfectly valid, and works just fine, but it does involve a dependency on the code-behind.  For something as presentation-oriented as displaying a sorted list of values, I don’t think that the XAML file should depend on the code-behind.

Here is a XAML-only approach to solving the problem.  First we need an unsorted enum:

Sorted enum in ComboBox (enum)

Next we need to create a sorted list of values in the enum, and then bind a ComboBox to that list:

Sorted enum in ComboBox (XAML)

(The System.ComponentModel namespace referenced above lives in the WindowsBase assembly.  I had to clip the assembly name in the image so that it would fit in my blog properly.)

The basic idea here is that we create a CollectionViewSource which, in turn, uses an ObjectDataProvider to get an unsorted list of values for the Animals enum.  The CollectionViewSource also has a SortDescription added to it.  That causes the list of enum values to be sorted in ascending order, based on their names.

Once that data source is declared we bind a ComboBox to it.  The ComboBox looks like this when you run the demo app:

Sorted enum in ComboBox (screenshot)

You can download the demo app here: Sorted enum in ComboBox (demo project)  Be sure to change the file extension from .DOC to .ZIP and then decompress it.


Creating a custom DataSourceProvider

June 19, 2007

In this blog post we will see how to create a subclass of DataSourceProvider which loads the text in a resource file, so that we may bind to it.

There are two very powerful ways to load an external data source in XAML, ObjectDataProvider and XmlDataProvider.  The former allows you to create an object via a parameterized constructor, invoke a method on an object, or invoke a static method – and then bind against whatever data it provides.  The latter allows you to load an XML file into an XmlDocument and bind against it.  Both of these classes derive from the DataSourceProvider base class.   WPF’s binding system has special knowledge of DataSourceProvider, and implicitly binds to its Data property.

We can create our own DataSourceProvider to perform tasks other than those listed above.  In this demo we will create a subclass which loads the text in a resource file.  That class will then be used to allow a TextBox to bind to the contents of a file, without needing to write a line of code.

Suppose that we are creating an application which must allow the user to enter and save a weekly status report.  One requirement of ours is that when the user creates a new status report they should be given some default text which makes it easier for them to write their report.  Here is a screenshot of a new status report in our app:

Custom DataSourceProvider (screenshot)

The text seen in the TextBox above is a status report “template.”  That template text is data, and data should generally be stored outside of the UI declaration.  In other words, we do not want to write that status report template in a XAML file, or in the code-behind.  It would be better if we could store it in a resource file, which is baked into our application’s assembly.  It would be even better if we had a simple and reusable means of loading the status report template directly into the TextBox, without needing to write code to load the status report text and put it in the TextBox.  The rest of this post demonstrates one way to achieve that goal.

First we create a text file in our project and put the status report template in it.  Here is StatusReportTemplate.txt:

Custom DataSourceProvider (text file)

Next we need to create the DataSourceProvider subclass which loads that text out of the file and exposes it.  That class is seen below:

Custom DataSourceProvider (ResourceTextProvider)

Now that we have our custom data source provider, let’s see how to bind a TextBox’s Text property to it:

Custom DataSourceProvider (XAML)

The Text binding has three settings applied to it, as discussed below.

Its Mode is set to ‘OneTime’ so that once the template text has been loaded, the binding system knows that it will never need to update the binding again. 

The Path property is set to “.”, meaning that we are binding directly to the value exposed by the ResourceTextProvider’s Data property.  If we were returning a complex type, we would specify the property name on the returned object to bind to.  Binding to “.” simply means to bind against the data object itself (in this case, bind to the string which contains the status report template).

The Binding’s Source is set to an instance of the custom data source provider.  The provider’s ResourceFile property is set to the name of the text file which contains the status report template.

That’s all there is to it.  Now that the ResourceTextProvider class exists, it could be reused in many situations to provide the text of a resource file.

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


Follow

Get every new post delivered to your Inbox.

Join 285 other followers