Wednesday, November 19, 2008   Search 
Links

 

Disciple
 Ask Dr. WPF Minimize
Author: Dr. WPF Created: 8/13/2007 5:15 PM
Do you have questions about Windows Presentation Foundation that might have broad appeal? Ask Dr. WPF!

A New Software Architecture Pattern: M-V-poo
By Dr. WPF on 1/23/2008 1:20 PM

I just saw a *GREAT* presentation by Josh Smith on using the Model View Controller (MVC) pattern to develop WPF applications.  Josh did an awesome job of breaking down the different pieces of the pattern into understandable parts and showing how each fits into a very simple WPF application.  And of course, he's already blogged about it

UPDATE:  1/28/08

Josh just posted this excellent Code Project article explaining his approach to MVC and unit testing in WPF.  It is a written version of the WPF Bootcamp presentation that he delivered at Microsoft last week.

The live presentation will eventually be available online in either streaming media or downloadable format and I will update this post with a link.

Those of us who have been writing WPF software for a while have (either consciously or subconsciously) moved to a similar architecture for our applications.  Such an architecture allows us to better leverage the power of the platform to separate UI design from the logic that is used to manipulate (or control) a view of the data.  There are many different variations of the pattern, including M-V-P (and variants), M-V-VM, or my version, which I'm choosing to call M-V-poo.

Every discussion I've seen on these software architecture patterns eventually ends with an argument amongst the purists as to whether specific functionality belongs in the controller (a.k.a., the presenter, the view model, the whatever); or whether the controller should really be allowed to reach into the view; or whether the controller should have any dependencies on a specific UI technology; or ad infinitum.

I anticipate seeing similar debates regarding Josh's example.  My favorite part of the talk was where he gave a nod to the purists and invited them to share such feelings with the caveat that he just doesn't care. 

We all recognize that in a perfect world, there would be a clear delineation of boundaries... but unfortunately we write software in the real world.  The cold hard fact is that there are definitely aspects of WPF (especially around things like commanding) that make it impractical to completely separate the presenter from the view.  The same thing can be said about every other UI platform I've seen thus far.  But WPF definitely gets us a lot closer to a perfect world than prior Windows technologies.

This leads me to my new pattern:  M-V-poo (because really, there just aren't enough architecture patterns! ).  My pattern acknowledges that there may indeed be "poo" within the view model, but it tries to minimize that poo (or at least make it less stinky) whenever possible.  Please feel free to use this pattern royalty free!

Comments (10)

Reflect On This
By Dr. WPF on 1/16/2008 4:58 PM

In a blatant attempt to put Lutz Roeder out of business (or at the very least, hasten the demise of his empire), today Microsoft released the source code for a number of .NET technologies, including Windows Presentation Foundation.  Seven Attorneys General have already vowed to investigate this act as a possible violation of the consent decree.  Read more here.


EDIT: 1/18/08

That's right... I did it!  I renamed this post and removed the 'M' word.

Why?  Because I do not want anyone to mistakenly associate me with these dolts (thanks for the tip, Brownie) who are addlepated enough to *actually believe* that this move by Microsoft represents monopolistic behavior.  They don't get it!  The source code was not released for their benefit, nor was it released to injure them...  It was released to help those of us who are actually writing Windows software.  It certainly has nothing to do with their little project to reinvent someone else's IP.

"Idiots!" 
          - Napoleon Dynamite

 

Comments (8)

Worth the wait... this app KaRocks!
By Dr. WPF on 1/8/2008 12:08 PM

When answering WPF questions, I like to provide pure markup samples, whenever possible.  I'm going to divulge a little secret now...  Whenever I post such a "XamlPad-ready" sample, there's a 98% chance that I've never actually tested it in XamlPad.  That's because I've been a kaxaml user since the 0.1 alpha release.

I've always liked kaxaml because of its "snippets" feature, but now there are many new reasons to really love this software.  (I'm not just saying this because Robby likes my snippets, either!)  Seriously, check it out!

(Ahhh... finally, I can cut and paste code directly from kaxaml into my forum posts... no more interim step of pasting into VS to get the syntax coloring!  And intellisense too!  Life is good. )

Comments (1)

ItemsControl: 'D' is for DataTemplate
By Dr. WPF on 1/3/2008 11:35 PM

The term "rich content model" is sometimes thrown around in WPF circles.  In this post, we examine this content model, especially as it pertains to items controls.

The WPF Content Model

In WPF, different classes of elements are categorized based on the type and number of their logical children.  We also refer to these logical children as the "content" of the control.  WPF defines several different "content models" for various different classes of elements.

The controls that can contain a single item (single logical child of type Object) are called "content controls".  These controls derive from the ContentControl base class.  Controls that can contain a collection of items (many logical children of type Object) are called "items controls".  These controls derive from the ItemsControl base class.  (These are the controls that we are focusing on in this ItemsControl series, so I'll come back to them shortly...)

If you took time to explore the different items controls at the end of The ICIQ Test, you know that there are also controls that contain a single header item plus a collection of content items.  These controls are called "headered items controls" and derive from the HeaderedItemsControl base class.  Similarly, there are controls that contain a single header item plus a single content item called "headered content controls" (which, of course, derive from the HeaderedContentControl base class).

Just to be complete, I should note that there are several other types of elements that have their own content models.  For example, a TextBlock can contain a collection of Inline items, which are text elements that derive from the Inline base class and are used to create flowing, formatted text.  A Decorator is an adorning element that can contain a single child of type UIElement.  A Panel is a layout element that contains a collection of UIElement items and is responsible for sizing and positioning those children.

The ItemsControl Content Model

So what's so special about the content model of ItemsControl?  Primarily, it allows the logical children of an ItemsControl to be any CLR objects.  This is fairly remarkable, if you think about it.  Traditionally, Windows developers have built up user interfaces by composing visual elements like buttons, labels, combo boxes, text boxes, etc.  But using WPF's rich content model (especially as it applies to the ContentControl and ItemsControl classes), it is now possible to build up a logical UI composed of both visual elements and data items.

To better understand this, consider the following simple example:

<Window x:Class="HomersListBox.Window1"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:src="clr-namespace:HomersListBox"
    Title="Homer's ListBox" Width="300" Height="400">
  <ListBox Width="200" Height="300">
    <src:Character First="Bart" Last="Simpson" Age="10"
        Gender="Male" Image="images/bart.png" />
    <src:Character First="Homer" Last="Simpson" Age="38"
        Gender="Male" Image="images/homer.png" />
    <src:Character First="Lisa" Last="Simpson" Age="8"
        Gender="Female" Image="images/lisa.png" />
    <src:Character First="Maggie" Last="Simpson" Age="0"
        Gender="Female" Image="images/maggie.png" />
    <src:Character First="Marge" Last="Simpson" Age="38"
        Gender="Female" Image="images/marge.png" />
  </ListBox>     
</Window>

In this example, the logical tree looks like this:


 
The Character object is a very simple CLR object with properties that identify characteristics of a cartoon character, such as strings to represent a first and last name, an int value to represent an age (normally, a person's age would be represented by a calculation performed on their date of birth, but most cartoon characters never actually age ), an enum value to represent a gender, and a string value that indicates a path to an image of the character.

When you run this little sample, you see the window shown here.

As you can see, the visual representation of the Character object is just a string.  If WPF does not know how to visually represent an object, it merely calls the ToString() method of the object to get a semi-meaningful textual representation of the item.

If you were to examine the element tree of the above sample using Snoop or Mole, you would see that WPF has conveniently inserted a TextBlock into the visual tree to display the string representation of the Character.  (Note that the TextBlock is part of the visual tree of elements, but it is not a member of the logical tree.  The visual tree consists solely of visual elements, whereas, the logical tree may consist of both visual and non-visual objects.)

This automatic TextBlock creation is the framework's default behavior whenever it needs to display string content within a ContentControl.  In this example, the ContentControl is a ListBoxItem (the item container for a ListBox).

In scenarios where you only want to present textual data, you can simply override ToString() in your data class and return an appropriate text description.  In our example, we could rewrite the Character class to return the character's name from its ToString() override, as follows:

    public override string ToString()
    {
        return _first + " " + _last;
    }

Then at least the text in our ListBox would be a little more representative of the data, as shown here.

But, of course, we want something a little better than just text.  Ideally, we'd like to have some formatted text along with an image of the character.  This is where a template comes in handy...

What is a Template?

In WPF, a template is just a tree of visual elements (along with some resources and triggers) used to define the look (and often behaviors) of a member of the logical tree.  As it builds the element tree, the framework watches for controls and data items that have corresponding templates.  When such an element is encountered, the appropriate template is "inflated" into the actual visuals that represent the logical item and those visuals are inserted into the visual tree.

There are different kinds of templates, each of which derives from the FrameworkTemplate base class.  The most common template classes are ControlTemplate and DataTemplate.  The ControlTemplate class is used to provide the visual representation for a control (like a ListBox).  This is the mechanism that enables the WPF lookless control model.

The DataTemplate class is used to provide the visual representation for a data item (like an item within the Items collection of a ListBox).  This is the template class we will use to define the visual appearance of our Character items.

Defining a DataTemplate

The first step is to actually define the DataTemplate.  In most cases, you will define it as a resource somewhere within your application.  For our example, let's just define it as follows in Window.Resources:

  <Window.Resources>
    <DataTemplate x:Key="CharacterTemplate">
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="100" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Image Margin="5" Source="{Binding Image}" />
        <StackPanel Grid.Column="1" Margin="5">
          <TextBlock FontWeight="Bold" Text="{Binding First}" />
        </StackPanel>
      </Grid>
    </DataTemplate>
  </Window.Resources>

Notice that our template tree consists of a root element (a Grid) containing several other visual elements.  Some of these visuals, like the Image and the TextBlock, contain properties with bindings set on them.  The notation to establish the binding is actually very simple.  It merely contains a path to a property of our Character object.

One important thing to notice is that we don't need to explicitly set a source for bindings within our data template (as long as we are binding to properties of the data item).  Since our template represents an actual item of data (a Character), WPF will automatically set that data item as the DataContext of the item container in which the template is inflated.  The root element of the template, and consequently, all descendants within the template, will inherit this data context.  In this manner, the data context is said to be implicit for elements in the DataTemplate.  Namely, the data context is the specific data item that the template represents.

Sidenote:  One of the most common questions I see in the WPF Forum is, "How do I get the corresponding data item when someone clicks a button within my data template?"  The answer should now be fairly obvious... just look at the DataContext of the original source of the routed event:

    private void OnButtonClick(object sender, RoutedEventArgs e)
    {
        object item = (e.OriginalSource as FrameworkElement).DataContext;
        . . .
    }

Using a DataTemplate with an ItemsControl

Now that we've defined a template, we need to somehow instruct our ItemsControl to use it for the data items within its Items collection.  There are actually several ways to do this.  The simplest approach is to explicitly set the template as the value of the ItemTemplate property of the ItemsControl, as shown here:

  <ListBox Width="200" Height="300"
      ItemTemplate="{StaticResource CharacterTemplate}">
    . . .
  </ListBox>

Now when we run our application, we see that our template is indeed being used to display each data item, as shown here.

Presto!  We now have a very simple example that uses a DataTemplate to define the visual representation of items within an ItemsControl.  Feel free to download this working sample, if you'd like to play with it and define a more impressive template!

Using a Type-Specific Data Template

In the example depicted here, we explicitly set the ItemTemplate for our ItemsControl.  Using this approach, every item within the Items collection will be displayed using the same template.  This is great for collections of similar objects, but what if you have a collection of disparate objects, as shown in the following markup?

<Page
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <ItemsControl Width="100" Height="100">
    <sys:Int32>30</sys:Int32>
    <sys:DateTime>12/16/1970</sys:DateTime>
    <sys:Boolean>True</sys:Boolean>
    <sys:Boolean>False</sys:Boolean>
    <sys:String>Foo</sys:String>
  </ItemsControl>
</Page>

This results in the following visual representation shown below:

Now suppose you want to use one template to display the Boolean values and a completely different template to display the other value types.  To enable this scenario, WPF allows you to specify a type-specific data template.

For example, you might decide that you want each Boolean value to be displayed as a checkbox, rather than the string "True" or "False".  To define such a type-specific data template, simply specify the DataType member on the DataTemplate declaration, as follows:

<Page
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <Page.Resources>
    <DataTemplate DataType="{x:Type sys:Boolean}">
      <CheckBox IsChecked="{Binding Mode=OneWay}" />
    </DataTemplate>
  </Page.Resources>
  <ItemsControl Width="100" Height="100">
    <sys:Int32>30</sys:Int32>
    <sys:DateTime>12/16/1970</sys:DateTime>
    <sys:Boolean>True</sys:Boolean>
    <sys:Boolean>False</sys:Boolean>
    <sys:String>Foo</sys:String>
  </ItemsControl>
</Page>

Now the ItemsControl is displayed as follows:

Notice that we did not specify an ItemTemplate at all in the above scenario.  Instead, when the framework needed to display a Boolean value in the ItemsControl, it performed a resource lookup for a type-specific template matching the Boolean type.  Since it found our template containing the CheckBox, it used it.  Without the template, it would have fallen back to the earlier observed behavior of calling ToString() on the object to get a textual representation for the Boolean value.

Defining a Default Template for a Given CLR Data Type

In our earlier example, we defined the Character template using a resource key (x:Key="CharacterTemplate").   We could have defined a default data template by instead using a DataType declaration, as follows:

  <DataTemplate DataType="{x:Type src:Character}">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Image Margin="5" Source="{Binding Image}" />
      <StackPanel Grid.Column="1" Margin="5">
        <TextBlock FontWeight="Bold" Text="{Binding First}" />
      </StackPanel>
    </Grid>
  </DataTemplate>

This produces a default visual representation for all Character objects that appear in the logical tree lower than the template declaration.  As such, if we do not specify the ItemTemplate property on the ListBox, this template will still be used to display the Character objects.  Furthermore, if we include a Character object as the content of a Button (or any other ContentControl), the same template will be used to represent the Character:

  <Button HorizontalAlignment="Center" VerticalAlignment="Center">
    <src:Character First="Maggie" Image="images/maggie.png" />
  </Button>

Sidenote:  If you're curious as to whether you can change the default template for all CLR objects, you cannot.  WPF specifically disallows data templates with DataType="{x:Type sys:Object}".  As such, you are stuck with the ToString() behavior for untemplated CLR objects.

Using a DataTemplateSelector

Assigning a default template based on data type is clearly very powerful.  Nonetheless, there may even be times when this does not give you the flexibility you need to select a data template for an item.  For example, suppose you want to use one template to represent characters under the age of 21 and a different template to represent those 21 and over.

(Okay, this age-based template selector is probably not a great example for cartoon characters... perhaps a different data template for girls and boys would be better... but honestly, that's too easy to achieve using a single data template with a data trigger... so humor me and let's just go with the age thing... )

For even more flexibility in selecting an item template, you can implement a custom data template selector.  A template selector is a class that derives from DataTemplateSelector and overrides the SelectTemplate method to return a template based on custom code execution.  Here is a very simple example to meet the needs described above:

public class CharacterTemplateSelector : DataTemplateSelector
{
    private DataTemplate _childTemplate = null;
    public DataTemplate ChildTemplate
    {
        get { return _childTemplate; }
        set { _childTemplate = value; }
    }

    private DataTemplate _adultTemplate = null;
    public DataTemplate AdultTemplate
    {
        get { return _adultTemplate; }
        set { _adultTemplate = value; }
    }
   
    public override DataTemplate SelectTemplate(object item,
        DependencyObject container)
    {
        if (item is Character)
        {
            return (item as Character).Age >= 21
                ? _adultTemplate : _childTemplate;
        }
        return base.SelectTemplate(item, container);
    }
}

Now to use the template selector, we simply declare an instance as a resource and set the ChildTemplate and AdultTemplate properties appropriately:

  <src:CharacterTemplateSelector x:Key="CharacterTemplateSelector" 
      ChildTemplate="{StaticResource CharacterTemplate}"
      AdultTemplate="{StaticResource AdultCharacterTemplate}" />

Then we set the ItemTemplateSelector property on the ItemsControl using a resource reference, as follows:

  <ListBox Width="200" Height="300"
      ItemTemplateSelector="{StaticResource CharacterTemplateSelector}">
    . . .
  </ListBox>

This custom data template selector is also included in the downloadable sample for this article.

What's next?

This ends our discussion on data templates and the WPF content model for the ItemsControl classes.  In the next episode, 'G' is for Generator, we will look at item containers and item container generators.  (And yes, I realize we're skipping a couple of letters, but you don't really want 26 posts on ItemsControl, do you?)

Comments (19)

ClipToBounds="Maybe"
By Dr. WPF on 12/28/2007 6:07 AM

Dear Dr. WPF,

I have set ClipToBounds="False" on the button in the following snippet, but it still clips its visuals.

<Page xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Background="AntiqueWhite">
  <Grid Width="150" Height="100" ShowGridLines="True">
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
    <Button Grid.Row="1" Grid.Column="1" Width="100" Height="75"
        ClipToBounds="False" Content="Test" />
  </Grid>
</Page>

How can I prevent this clipping?

Thanks,
JC


Hi JC,

Yes, ClipToBounds is a bit of a misnomer.  Conceptually, you can think of the ClipToBounds property as a toggle between "True" and "Maybe".

As I describe in this forum post, the framework uses additional criteria (see Additional Clipping Criteria for Framework Elements below) besides ClipToBounds when determining the clipping geometry for a framework element.  As such, setting ClipToBounds="False" will not prevent clipping.

In that same post, I describe a trick that will prevent the clipping from occurring. Namely, you can wrap the elements that should not be clipped (e.g., your button) in a Canvas.  Since a Canvas always arranges each child at its "desired size" (see Explanation of "Desired Size" below), the element assumes there is no need for clipping and won't even try to clip its content.

Below is your snippet modified to use a Canvas in this manner.

<Page xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Background="AntiqueWhite">
  <Grid Width="150" Height="100" ShowGridLines="True">
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
    <Canvas Grid.Row="1" Grid.Column="1" >
      <Button Width="100" Height="75" Content="Test" />
    </Canvas>
  </Grid>
</Page>

Additional Clipping Criteria for Framework Elements

If you are curious about the other criteria that is used to determine a clipping geometry, it is quite simply based on the "desired size" of the child.  As I explain in this post, if a child's desired size is larger than the size of the rect used to arrange the child, then the arrange rect actually becomes a "clipping rect" for the child element.  More specifically, when the element is rendered, it's GetLayoutClip() method will use the arrange size to determine a clipping geometry.

Explanation of "Desired Size"

WPF uses a 2-pass layout cycle in which a parent element first measures and then arranges each child.  During the measure pass, the parent calls the Measure() method (inherited from UIElement) of each child and the child responds, in turn, by measuring each of its own children.  This logic is located within the MeasureOverride() function of the child.  This results in a recursive drill-down into the visual tree for the measure pass.  Once it has measured its children, the child returns its "desired size" based on those measurements.  This resultant desired size is the value returned from the MeasureOverride() function and is thereafter accessible on the child via its DesiredSize property.

Sidenote:  There is a similar recursive drill-down for the arrange pass.  The arranging of child elements happens within ArrangeOverride().  The size returned from ArrangeOverride() becomes the element's "render size" and is accessible via its RenderSize property.

Supporting ClipToBounds="False" in Custom Elements

If you would like to write elements that actually support ClipToBounds="False", it is actually very simple.  Just override the GetLayoutClip() method as shown in the following class:

public class MyButton : Button
{
    protected override Geometry GetLayoutClip(Size layoutSlotSize)
    {
        return ClipToBounds ? base.GetLayoutClip(layoutSlotSize) : null;
    }
}

Et voîla!  This custom button will treat ClipToBounds as the boolean that it claims to be!  A value of 'true' means clipping occurs and a value of 'false' means no clipping occurs.

I wish the framework developers would have taken this approach.  Or an even better (although less intuitive) design would make ClipToBounds a nullable boolean with a default value of null.  The null value would essentially represent the current "Maybe" behavior and a value of false would represent the approach demonstrated above.

As always, I hope this helps!

Cheers,
Dr. WPF

Comments (1)

My WPF Code Snippets
By Dr. WPF on 12/17/2007 7:32 AM

Yikes!  Has it really been over a month since my last blog entry!?!

Okay, the last 6 weeks are a bit hazy and I wish I could blame my absence from the WPF Forum (and this blog) on something exciting, but honestly, it's just been work.  A number of projects all converged at once creating "the perfect storm" of work engagements.  And although I love writing WPF code, I'm now hoping for a small respite from the daily deadlines.  Hopefully, the next few weeks will be a little more tame and I will be able to catch up with life in the WPF community.

Whenever we go through these crunch times, I realize how much I've come to depend upon the code snippet support in Visual Studio 2005/2008.  I totally rely on my WPF code snippets... and its not just because of the time they save me writing code, but also because of the consistency they bring to my code.  I can look at any WPF classes I've written over the past few years and immediately understand what is going on in the properties, events, and commands exposed by those classes.

If you do not yet have a good set of Visual Studio code snippets, I would encourage you to develop them.  I have posted my C# WPF snippets here for anyone who is interested in perusing, adopting, or improving them. 

<UPDATE>

January 4, 2008:  The downloadable snippets file now contains a .vsi file that can be used to directly import these snippets into Visual Studio 2005/2008.  (Special thanks to the coworker who was nice enough to create the install package for me!)

</UPDATE>

(Apologies to the VB.NET WPF developers out there...  I have never ported these to VB, as the time I spend writing VB code is extremely limited.  But if anyone is up for a challenge and wants to port these and send them my way, I'd be happy to post the equivalent VB snippets on my site.)

<UPDATE>

September 22, 2008:  I finally got around to porting these snippets to VB.  See this post for the details.

</UPDATE>

I have designed these snippets to cover 98% of the usage scenarios that I encounter in a typical WPF development project.  I have also designed them to enforce good coding patterns, especially around consistency and documentation.

I won't spend a lot of time explaining how to use them (because hopefully they are self-explanatory for WPF developers).  There are really only three shortcut keywords to remember:

  • dp  (for dependency properties)
  • rc  (for routed commands)
  • re  (for routed events)

From there, it's just a matter of choosing the correct snippets from the context menu.  I've found that I can now invoke most of my snippets without even thinking about the keystrokes... my fingers just go into "auto" mode ( d - p - <tab> - <tab> - 2 - <enter> - property name - property type - ... ). 

Of course, I created the blasted things, so maybe I'm not a representative sample. 

In addition to the WPF-specific snippets, I've included a couple of other snippets in this zip that I also use quite a bit... "pc" provides the PropertyChanged implementation for the INotifyPropertyChanged interface and "pcp" is used to define a property that raises such a change notification. 

I'm looking forward to a day when I'll be able to do more advanced things in my snippets (custom functions, custom formatting, capitalization, custom placement for different code parts, etc).  In the meantime, I hope others will find my existing snippets useful!

Cheers,
Dr. WPF

Comments (20)

Can I borrow that DP for a little while?
By Dr. WPF on 11/14/2007 7:23 PM

If you're like me, you sometimes want to prove out a concept in XAML before implementing the "real" solution.  For example, you may want to create a new control which is very similar to an existing control, but lacking a property or two.  Rather than derive the control from a base class and add the new properties, it might be nice to simply re-template the existing control and pretend that it has the necessary properties.

Luckily, WPF makes this fairly easy through its support for attached properties.  It's very likely that the framework has already defined a couple of properties of the very type you are needing.  If you cannot find an exact match, you can usually find something close enough.

Anyone who follows my posts in the WPF forum knows that I'm a big fan of "borrowing" attached properties from the framework.  This is especially useful in the forum because it allows me to provide a XamlPad-ready solution to demonstrate a concept.  Here are a couple of examples:

Over the years, I have assembled a catalog that includes most of the framework-defined, public attached DPs (yes, I've spent far too many hours in reflector and writing code that greps the framework ), as well as all of the relevant information about those DPs.  For anyone who is similarly inclined to "borrow" from the framework, here is my spreadsheet of attached DPs.

A few words of caution... 

  • You should always know what the owner class does with any property you borrow. 
  • You should pay attention to default values and inheritance.  Sometimes you need a bool property with a default value of true... other times you may want a default value of false.  Sometimes you need a property that inherits... other times you explicitly don't want inheritance.  (Borrowing a property like TextElement.FontSize could really screw up things lower in the tree.)
  • The owner class may sometimes define a PropertyChangedCallback that will interfere with your ability to use the property as you wish.  Always know what the owner class does with the property.
  • The owner class may provide a validation routine for the property that prevents you from entering the value you want to specify.  Again, always know what the owner class does with the property.
  • The property may be registered in a manner that makes it costly perf-wise, such as FixedPage.Bottom which invalidates the parent's arrange anytime the property changes on an object.  Sometimes you may explicitly want this behavior... other times it will just unnecessarily cause layout passes.  Again, always know what the owner class does with the property.
  • If you use a property in a scenario where the framework itself is trying to use the property (such as TextSearch.TextPath on an ItemsControl), you are liable to find yourself in contention with the framework.

Okay, I'm sure I could go on, but you get the general idea.

The nice thing about this spreadsheet is that it has all of the information you might want to know about the properties, including the following:

  • Defining Class / Owner Type
  • Property Name
  • Type
  • Metadata Type
  • Default Value
  • Owner Handles Changes (the owner registered a PropertyChangedCallback)
  • Coerced (the owner coerces the value)
  • Validation (the owner validates the value)
  • Inherits
  • Metadata Options

It also contains a second worksheet with a pivot table that can be used to easily filter the properties down to exactly those that meet your needs.  And remember, if you can't find a property that matches the exact type you're looking for, you can usually just use a DP of type string because there are type converters for most objects that are capable of translating to/from string values.  And there are a few properties of type 'object' that can serve as uber-utility DPs.

Let the borrowing begin!
Dr. WPF

Comments (1)

A trigger for the MenuItem directly under the mouse (deja vu)
By Dr. WPF on 11/6/2007 6:02 AM

By (indirect) request, I have put together a helper class that provides a property that can be used as a trigger to determine if a MenuItem is directly under the mouse.  This is analogous to this solution offered by Mike Hillberg for dealing with the TreeViewItem directly under the mouse. 

Mike does a good job of explaining the general problem and solution, so I highly recommend that you read his post!

The MenuItem scenario has its own set of issues to overcome, most of which arise from the fact that submenu items are very often disabled (due to application state).  Things are further complicated by the fact that the subitems are presented within a Popup.  I will leave it as an exercise for the reader to review my approach to see how I dealt with these issues (because I'm just too lazy to explain myself right now ).

Here is the code for the MenuHelper class (open source, as always) and here is a sample app that demonstrates its usage.  Note that the sample class randomly disables menu items to simulate the changing state of an application.

Hope this is useful.  Let me know if you encounter any issues with the helper class.

Cheers,
Dr. WPF

Comments (1)

ItemsControl: 'C' is for Collection
By Dr. WPF on 11/5/2007 5:06 PM

The series continues... 

An ItemsControl would be nothing without its collection of Items.  In this post, we investigate the "Items" of an ItemsControl, looking at each of the following areas:

If I were rating the technical level of each post in this series, I would put this particular post somewhere in the range of moderate to advanced (but still very approachable ).

The Items Collection (a.k.a, the ItemCollection)

The "Items" property of an ItemsControl provides access to a collection of objects, or data items, that make up the logical content of the control.  The type of this property is ItemCollection.  (I will use the terms "Items collection" and "ItemCollection" interchangeably.)  The "Type" of each item within the Items collection is Object.  So literally any CLR object can be added to an ItemCollection.

We will look at the ItemCollection class, itself, in more detail momentarily, but first, there are a couple of things to note about the Items property declaration on ItemsControl.

1) The Items property is a read-only CLR property.

This means that the collection exposed via the Items property must be instantiated by the control itself.  In fact, the ItemCollection class does not even provide a public constructor.
 
2) The Items property is not backed by a dependency property. 

This means that you cannot set a binding directly on the Items property.  However, you can definitely bind an ItemsControl to a collection of items.  We will look at how this works shortly, but before we do, we should look at the simpler, non-databound (or direct) scenario... 

ItemCollection Modes:  Direct and ItemsSource

Although the Items property is read only, the provided collection is not necessarily read only.  In fact, in earlier posts, we've already seen that you can directly add items to an ItemsControl:

<ListBox>
  <sys:String>Item 1</sys:String>
  <sys:String>Item 2</sys:String>
  <sys:String>Item 3</sys:String>
</ListBox>

Because items are added directly to the ListBox, this is an example of using an ItemCollection in "direct mode".  This is by far the simplest mode to use conceptually.  In direct mode, the ItemCollection class works exactly like every other .NET collection.  You can directly access all of the expected members of an indexed collection:  Add(), Insert(), Remove(), RemoveAt(), IndexOf(), Items[index], Count, etc.

The other mode for an ItemCollection is called "ItemsSource mode".  In ItemsSource mode, the items in the ItemCollection correspond to items in a source collection.  That source collection is specified via a separate property on the ItemsControl that is appropriately named "ItemsSource". 

The following shows a typical scenario of an ItemsControl using ItemsSource mode:

<ListView ItemsSource="{Binding Path=Characters}">
  <ListView.View>
    <GridView>
      <GridViewColumn Width="100"
        DisplayMemberBinding="{Binding Last}"
        Header="Last Name" />
      <GridViewColumn Width="100"
        DisplayMemberBinding="{Binding First}"
        Header="First Name" />
      <GridViewColumn Width="60"
        DisplayMemberBinding="{Binding Gender}"
        Header="Gender" />
    </GridView>
  </ListView.View>
</ListView>

The ItemsSource property is a dependency property of type IEnumerable.  This tells us two important things:
 
1) The source collection can be any enumerable collection.

2) The ItemsSource property can be established using a binding.

As such, it is the ItemsSource property (in conjunction with the ItemsSource mode of an ItemCollection) that enables an ItemsControl to be databound to a collection. 

Sidenote: Although you will most often see the ItemsSource property of an ItemsControl set via a binding, there is no reason that the ItemsSource property cannot be directly set to an enumerable collection, as shown here:

<ListBox ItemsSource="{StaticResource Characters}" />

The Modes are Mutually Exclusive

It should be noted that direct mode and ItemsSource mode are mutually exclusive.  An ItemCollection is either in direct mode or in ItemsSource mode, but never both. 

Once Items have been explicitly added to the Items collection, it is in direct mode.  A subsequent attempt to set the ItemsSource property after entering direct mode will result in an exception. 

Similarly, once the ItemsSource property has been set, the Items collection is in ItemsSource mode.  A subsequent attempt to directly modify the Items collection (using Add(), Insert(), Remove(), etc) will result in an exception.

The only way to change modes at runtime is to either 1) clear the Items collection via the Clear method (if in direct mode) prior to setting the ItemsSource property, or 2) set the ItemsSource property to null (if in ItemsSource mode) prior to calling the direct access methods of ItemCollection.

Observable Collections Support Dynamic Updates

As noted earlier, in direct mode, changes to the Items collection are made through direct access methods of the ItemCollection class.  Any such direct changes made at runtime will cause the visuals to be updated immediately. 

But what about dynamic collection changes in ItemsSource mode?  How could the Items collection possibly know about changes to the source collection?

The answer is that the ItemCollection cannot know about any such changes unless the source collection chooses to announce those changes by providing change notifications.  The way a source collection does this is by fully implementing and supporting the INotifyCollectionChanged interface.  Any collection that provides these change notifications is said to be observable.

Dynamic changes to an observable collection will be immediately reflected in the Items collection of any ItemsControl that is bound to the collection.  Consequently, these changes will be immediately reflected in the user interface.

The INotifyCollectionChanged interface is not super complex, but ensuring proper implementation does place an extra burden on the source collection.  If developers had to implement this interface anytime they wanted to bind to a collection, it would be a huge inconvenience.  Luckily, the .NET framework provides a very handy generic template class called ObservableCollection<T>.  By creating an instance of this class, you automatically get all of the change notifications without having to do any extra work.

Typically, you will see a collection class derive from ObservableCollection<T>, to create a strongly typed collection, as follows:

    public class StringCollection : ObservableCollection<string>
    {
    }

Any instance of this StringCollection class is fully observable and will serve well as the ItemsSource of an ItemsControl.  It can be used exactly like an instance of Collection<string>.

So what if the collection is not observable?  Can it still serve as an ItemsSource?  

Absolutely.  As noted earlier, any enumerable collection can serve as the source of an Items collection.  The only caveat is that the Items collection will not be updated dynamically if the source collection changes at runtime.  Rather, the collection will be enumerated once and its members will be added to the Items collection when the ItemsSource property is first established.  Thereafter, if you want the Items collection to be updated, you must explicitly call the Refresh() method of ItemCollection.

CollectionView: "The Great Equalizer"

If you've worked with ItemsControl much, you probably know that sorting, grouping, and filtering are supported via the CollectionView class.  This class also supports the notion of currency, which means a CollectionView maintains a current item pointer that can be accessed and moved using methods on the CollectionView.

Every enumerable collection in WPF has a default view.  The collection may have multiple other views, each with its own sorting, grouping, and filtering parameters.  A common way to establish a view of a collection in markup is to leverage the CollectionViewSource class, as shown here:

<CollectionViewSource x:Key="characterView"
    Source="{StaticResource Characters} ">
  <CollectionViewSource.SortDescriptions>
    <componentModel:SortDescription PropertyName="First" />
  </CollectionViewSource.SortDescriptions>
  <CollectionViewSource.GroupDescriptions>
    <dat:PropertyGroupDescription PropertyName="Last" />
  </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

This CollectionViewSource can then be specified as the ItemsSource of an ItemsControl, thereby causing its associated view of the collection to serve as the CollectionView for the control.

"But Dad, I don't WANT a CollectionView!"
"I didn't ask what you WANT...  As long as you're living under my roof, you'll use a CollectionView!"

With WPF, sometimes it's not as much about what you want, as it is about what the framework needs.  The CollectionView class is a classic example.  When it comes to binding controls to a collection of data items, the framework needs a way to treat all collections in a consistent manner. 

Unfortunately, not all enumerable collections were created equal.  For example, IList provides direct index-based access to items, whereas IEnumerable requires that you enumerate all items starting from the beginning of the collection until you come to the index you care about.  For another example, consider a collection class that supports the INotifyCollectionChanged interface to provide collection change notifications versus a simple Collection<T> class that provides no such notifications.

The framework architects wanted to support binding to as many different types of collections as possible.  But imagine how ugly the code for the ItemsControl class would be if it had to account for differences among collection types with conditional code blocks...  if it's an observable collection, do this, or if it's an IList, do this, or if it's an IEnumerable, do this, etc. 

Enter the CollectionView class...
 
To deal with this challenge of disparate collections, WPF introduces the CollectionView class to serve as the great equalizer of enumerable collections.  It is the CollectionView class that internally looks at a collection's supported interfaces and determines how best to deal with the collection.  It then surfaces a view of the collection through a well-defined set of properties, methods, and events.  Essentially, it allows all collections to be treated by the ItemsControl class as equals.

So whether or not you care about currency, grouping, sorting, filtering, change notifications, etc., the Items collection of an ItemsControl is always maintained internally using a CollectionView.  In fact, the ItemCollection class is a CollectionView. 

Although true, that last statement is a little misleading since really, ItemCollection is just a wrapper class for an internal CollectionView member.  The type of the internal CollectionView is determined by the type of the source collection and the mode of the ItemCollection.  In Direct mode, it is always of type InnerItemCollectionView (an internal class designed specifically for direct mode views).  In ItemsSource mode, it will be of type CollectionView for an IEnumerable source, ListCollectionView for an IList source, or BindingListCollectionView for an IBindingList or IBindingListView source.

So you're observable...  Who cares?

CollectionView does.  We've already noted that dynamic changes to observable collections are immediately reflected in the Items collection.  It is the CollectionView class that actually listens to the events raised by the collection.  So if you've ever wondered exactly who is monitoring these events, get a life!  Sorry...  I meant to say, it's CollectionView.  Now you know.

Performance Considerations around Bound Collections

Keeping in mind that CollectionView serves as the great equalizer of collections, we should look at some performance considerations around binding to collections.  We've already acknowledged that not all collections support the same features.  Often, CollectionView must perform extra work to support its common interface for collections.

One of the major features provided by CollectionView is indexing for an enumerable collection.  That is, CollectionView provides direct access to members of the collection by an integer-based index.  This means it must support properties like this[int index] and Count, as well as methods like Contains() and IndexOf().

If the source collection already supports indexing, you will see much better performance when binding to the collection.  This means that the best candidates for a source collection are those that support the IList interface.  It should be noted that ObservableCollection<T> implements IList, so it's a great choice.

If the source collection does not support index-based access (ICollection or IEnumerable, for example), then CollectionView must do a lot more work to surface the view as an indexed collection.  In order to support a property like Count, it may be necessary to enumerate the entire collection.  And some methods like Contains(), IndexOf(), and GetItemAt() can be super expensive, since the performance of the algorithm to support these operations is directly proportional to the size of the collection.

So the key perf takeaway is that the source collection should support IList whenever possible.

Items and the Element Trees

The items within the Items collection make up the logical children of the ItemsControl.  They are said to be members of the logical tree.  For a HeaderedItemsControl, the headers associated with each item will also be logical children of the ItemsControl.  (Btw, if you're not sure what a HeaderedItemsControl is, you should revisit "The ICIQ Test" and spend a little more time exploring the tooltips after receiving your score.)

If the items in the Items collection happen to be visuals, then they will also be members of the visual tree.  If they are not visuals, they will instead be represented visually using an inflated template of visuals.  Since the template represents data items, it is called a DataTemplate.  For more on that, please tune in for the next episode in this series... 'D' is for DataTemplate.

Comments (4)

Continuing Quest for "Star"-dom
By Dr. WPF on 10/25/2007 4:45 PM

I just noticed that it's been exactly two months since I joined the MSDN forums, so here's my two-month update on my quest for 5 gold stars...

MSDN Profile

At the moment, I have exactly 3500 points, which puts me solidly in the middle of 3 stars.  I'm not quite half way to my 4th star (7500 points).  And at this rate, I should achieve my 5th star (15000 points) about 6 months from now.  Then I will finally be able to retire into obscurity (unless people start haphazardly marking all of my posts as helpful, in which case I could retire sooner)!   

It's quite clever of Microsoft to invent this little rating system that takes full advantage of the obsessive-compulsive nature of geeks to defend their geekdom.

Comments (4)


 Print   
Copyright 2007 by Dr. WPF   Terms Of Use  Privacy Statement