Attached Behaviors are the New OLE (a.k.a. Long Live Components)

Pruning through the old Google Reader starred items list was supposed to only take me an hour or so Saturday morning. But sandwiched between some other diversions, it ended up taking me the whole weekend. One of the last things I read was
Mac OS X 10.6 Snow Leopard: the Ars Technica review
(that was an hour right there all by itself). Flipped through some of the old Mac OS X articles, particularly those right at the turn of the Classic Mac OS transition almost ten years ago. You remember Classic Mac OS, right? With Cyberdog and OpenDoc? Windows users will remember the ideas more as OLE and its foundation COM, and a generation of applications where the screen jumped to and fro whenever you clicked somewhere you weren’t supposed to as menubars popped up and disappeared. And of course, there was J2EE .

Maybe these technologies suffered from being too ambitious or too undefined in scope, but for whatever reason, they’ve been consigned to the dustbin of history. But the dream of having arbitrary components that could just be snapped together like building blocks never seems to die, and maybe we’re finally reaching the point in technology’s history where that could be a possibility. OLE, OpenDoc, and J2EE all assumed those building blocks were gigantic—plug six or seven them together and boom, you’ve got an app—whereas realistically, they’re probably much closer to LEGO®-sized. You’ll need a lot of them before you get something that makes sense—and consequently, you need a little bit of computer know-how.

Fellow Lab49er Charlie Robbins blogged a few weeks ago about a few
sample Silverlight projects that added physics-based behaviors to a canvas with a few items in it. It’s downright silly what you can do with behaviors now, and I wonder if we’re not too far off from seeing a scaled-down version of the component dream realized. It always seemed like overkill to have an IntegerTextBox, or a DateTextBox. But an IntegerBehavior/DateBehavior that can be applied to a TextBox, or a grid cell? Or a behavior that could be applied to a Label to make it an editable TextBox upon a double-click? Or better yet, two behaviors, one to make a label editable on a double-click, and another to restrict to date entry? Much more awesome…

If you haven’t read up on attached behaviors yet, you should. I would argue that a proper MVVM design necessitates attached behaviors—they’re everything that doesn’t belong in the viewmodel layer, but since your views should be stupid and codeless, your “enforce integerness” behavior has to end up somewhere. With viewmodels and attached behaviors, you might never need to write another line of code-behind ever again. —DKT

Links O’Clock; 2009.09.25

Normally, throughout the week, I star a whole bunch of things in Google Reader that I want to go back to when I’m not busy jostling for space on the New York subways or when I’m back at my comfortable desk at home with my giant monitors. Unfortunately for me, I star articles about 500% faster than I can read them, so every once in a while, I have to give myself a weekend dedicated to purging that star list so that I don’t forget about things that I really really did want to read (Mr. Siracusa doesn’t write as often as most people, but he makes up for it).

So it’s time for the first-ever Links O’Clock here; most of these articles go back at least two months or more, but hey, maybe you missed it the first time the Internet collectively decided they were worth reading. I don’t think Links O’Clock will normally be this long, but we’ll see.

Also gonna try giving Google Reader’s “Shared items” feature a ride—I keep hitting it by accident in my main newsreader, but now I’ll hit it on purpose (link).


It seems fitting that my desire to purge my starred article backlog leads me to this article likening obesity to information overload:
http://www.core77.com/blog/featured_items/no_more_feeds_please_how_abundant_information_is_making_us_fat_14248.asp

I once tried using a 3D designing app once. I flung the mouse out the window in disgust after several hours of hair-pulling madness. This would have been a far more entertaining experience:
http://www.ilovesketch.com/

For those of you trying to skin your latest GUI, you might be tearing your hair out trying to pick perfect colors. Don’t go bald—just use this:
http://colorschemedesigner.com/

Matthias Shapiro talking about effective visualization with some very concrete and awesome examples—it’s an Ignite Show video, so it’s five minutes long, which is about the longest video I’ll watch before I start wishing I had my computer hooked up to my TV:
http://www.designerwpf.com/2009/09/16/now-playing-on-the-ignite-show/

Another interesting visualization by Ben Fry—living in this country is often defined by driving, so I shouldn’t be so surprised that roads alone do such a remarkable job punctuating the landscape:
http://benfry.com/allstreets/index.html

I’m always a sucker for a good how’d-they-done-it story: The making of the NPR News iPhone App, complete with mockups, requirements identification and gathering—all that good process-y stuff:
http://www.npr.org/blogs/inside/2009/08/the_making_of_the_npr_news_iph.html

If you’re working on building iPhone applications and you want to generate super-realistic pictures of what your app will look like before you even install the Developer Tools:
http://mockapp.com/

Another UI mocking tool for iPhone apps, but you’ll have to write a little code
http://giveabrief.com/

—DKT

More 2D/3D Tricks: ItemsControl3D

Building on some of the cute tricks of using a Viewport3D as a two-dimensional surface, we can actually devise a fully-bindable System.Windows.Controls.ItemsControl that renders to a Viewport3D instead of a Panel. It turns out to all be quite remarkably simple:

  1. Define a class, ItemsControl3D, that will be our magic Viewport3D-holding ItemsControl.
  2. Build a ControlTemplate that contains a Viewport3D with a named ModelVisual3D whose children will be modified as the ItemsControl sees fit.
  3. Override GetContainerForItemOverride() to provide instances of ItemsControl3DItem as the “container” for the individual items in the ItemsControl:
    1. Make the “container” item a zero-size, completely non-visible FrameworkElement.
    2. Create an ItemsControl3DItem.Geometry property; this Geometry3D object will be used to populate the ModelVisual3D in our Viewport3D.
  4. I additionally chose to implement container recycling (in some early drafts of ItemsControl3D, it cut processor usage down 25%).

First, the static constructor:

1
2
3
4
5
6
7
8
9
10
11
12
static ItemsControl3D()
{
    DefaultStyleKeyProperty.OverrideMetadata(
        typeof(ItemsControl3D),
        new FrameworkPropertyMetadata(typeof(ItemsControl3D)));
 
    ItemsPanelProperty.OverrideMetadata(
        typeof(ItemsControl3D),
        new FrameworkPropertyMetadata(
            new ItemsPanelTemplate(
                new FrameworkElementFactory(typeof(ItemsControl3D.ItemsPanel)))));
}

The first line should be familiar to those in the audience who have authored custom controls before; it merely indicates that somewhere, WPF should expect to find:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<<b>Style x:Key="{x:Type ThreeDee:ItemsControl3D}"</b>
        TargetType="{x:Type ThreeDee:ItemsControl3D}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ThreeDee:ItemsControl3D}">
        <Border>
          <Grid>
            <Viewport3D Name="PART_Viewport">
              <Viewport3D.Camera>
                <OrthographicCamera
                         Position="0,0,1" LookDirection="0,0,-1" UpDirection="0,1,0"
                         Width="{Binding Path=ActualWidth, ElementName=PART_Viewport}"/>
              </Viewport3D.Camera>
 
              <ModelVisual3D>
                <ModelVisual3D.Content>
                  <AmbientLight Color="White">
                </ModelVisual3D.Content>
              </ModelVisual3D>
 
              <ModelVisual3D x:Name="PART_SceneRoot"/>
            </Viewport3D>
 
            <ItemsPresenter/>
          </Grid>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

The line after that (the overriding of the ItemsPanel metadata) indicates that for all ItemsControl3D, the default Panel presenting children for the panel should be ItemsControl3D.ItemsPanel. This is an inner class that we’ve defined that is specially crafted to hold the child elements of the ItemsControl.

In the style, we’ve given one of the ModelVisual3D children a name (PART_SceneRoot); that’s because in OnApplyTemplate(), we’re going to look for it and use that as the place to hold the 3D objects that we generate.

We override a trio of methods in order to perform basic container housekeeping. GetContainerForItemOverride() either creates a new container or reuses an existing one; ClearContainerForItemOverride(…) adds an unused ItemsControl3DItem back to the pool; IsItemsItsOwnContainerOverride(…) is useful to override if you wanted to manually create and add ItemsControl3DItem objects to the ItemsControl3D.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private readonly Stack<ItemsControl3DItem> _unusedContainers =
        new Stack<ItemsControl3DItem>();
 
protected override DependencyObject GetContainerForItemOverride()
{
    if (_unusedContainers.Count == 0)
    {
        return new ItemsControl3DItem();
    }
    else
    {
        return _unusedContainers.Pop();
    }
}
 
protected override void ClearContainerForItemOverride(
    DependencyObject element, object item)
{
    _unusedContainers.Push((ItemsControl3DItem)element);
}
 
protected override bool IsItemItsOwnContainerOverride(object item)
{
    return (item is ItemsControl3DItem);
}

Lastly, the actual “panel” that the ItemsControl thinks is doing the work:

1
2
3
4
5
6
7
8
9
10
11
12
13
private new sealed class ItemsPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        var ic3d = (ItemsControl3D)GetItemsOwner(this);
        if (ic3d != null)
        {
            <b>ic3d.UpdateViewportChildren(InternalChildren);</b>
        }
 
        return Size.Empty;
    }
}

And that’s all the panel needs to do. The magic method call is actually the property accessor Panel.InternalChildren—internal code in Panel works together with ItemsControl in order to derive the appropriate children (this is ultimately what will cause GetContainerForItemOverride() and other methods to be called).

Lastly, the private method UpdateViewportChildren in ItemsControl3D:

private void UpdateViewportChildren(UIElementCollection children)
{
    if (_sceneRoot == null) return;
  
    _sceneRoot.Children.Clear();
    foreach (ItemsControl3DItem item in children)
    {
        var m = item.Model;
        if (m != null)
        {
            _sceneRoot.Children.Add(m);
        }
    }
}

And in case you were wondering, ItemsControl3DItem at a high level:

1
2
3
4
5
6
7
8
public class ItemsControl3DItem : FrameworkElement
{
    public double X { get; set; }
    public double Y { get; set; }
    public Brush Background { get; set; }
    public Geometry3D Geometry { get; set; }
    public ModelVisual3D Model { get; }
}

The properties of ItemsControl3DItem (X, Y, Background, Geometry) are all used to determine the Model property.

You can use an ItemsControl3D in XAML as easily as any other subclass of ItemsControl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ThreeDee:ItemsControl3D ItemsSource="{Binding ...}">
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="{x:Type ThreeDee:ItemsControl3DItem}">
            <Setter Property="X" Value="{Binding Year}"/>
            <Setter Property="Y" Value="{Binding Profit}"/>
            <Setter Property="Background" Value="Blue"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
 
    <!-- you could also hardcode children in the control just like 
         ListBoxItems in a ListBox or ListViewItems in a ListView -->
    <!-- <font color="#555555"><ThreeDee:ItemsControl3DItem X="5" Y="6" Background="Blue"/>
         <ThreeDee:ItemsControl3DItem X="2" Y="3" Background="Red"/></font> -->
</ThreeDee:ItemsControl3D>

It should be noted that this exact technique can be used to generate full-blown three-dimensional visualizations with nothing more than basic ItemsControl-style bindings. Coupled with an abstract data model, you’ve got yourself a pretty canvas to paint with, and it’s pretty responsive to updates as well and doesn’t blow a hole through your CPU either. The sample app updates all of the values in a collection of 1,000 points, ten times a second, while using less than 10% of my two-year-old MacBook’s CPU.

The Sample Code: ItemsControl3D.zip

—DKT

Sept 24: Fixed the problems with the download. Of course, since the AssemblyInfo.cs file was missing, the [assembly:ThemeInfo(ResourceDictionaryLocation.SourceAssembly)] tag was missing too—that caused the default template that I defined for ItemsControl3D to not be found. This is fixed now.

2D in a WPF 3D World

It’s a fairly common and standard trick to take advantage of the hardware acceleration afforded by modern graphic cards and render two-dimensional figures in 3D. Here is a simple and fast way to take the 3D out of a Viewport3D:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<Viewport3D>
  <Viewport3D.Camera>
    <OrthographicCamera Position="0,0,1" LookDirection="0,0,-1" UpDirection="0,1,0"
                        Width="{Binding ActualWidth}" Height="{Binding ActualHeight}"/>
  </Viewport3D.Camera>
 
  <ModelVisual3D>
    <ModelVisual3D.Children>
      <!-- render colors...relatively properly -->
      <ModelVisual3D>
        <ModelVisual3D.Content>
          <AmbientLight Color="White"/>
        </ModelVisual3D.Content>
      </ModelVisual3D>
 
      <ModelVisual3D x:Name="SceneRoot">
        <ModelVisual3D.Content>
          <!-- this is where stuff you want to render actually goes -->
        </ModelVisual3D.Content>
      </ModelVisual3D>
 
    </ModelVisual3D.Children>
  </ModelVisual3D>
</Viewport3D>

When the camera is set up this way, the center of the Viewport3D represents (0,0). The bottom-left is (−width / 2, −height / 2) and the top-right is (+width / 2, +height / 2).

Now what can you put in something like this? Same thing you’d normally put in a Viewport3D:

1
2
3
4
5
6
7
<Model3DGroup>
  <GeometryModel3D Geometry="...">
    <GeometryModel3D.Material>
      <DiffuseMaterial Brush="..."/>
    </GeometryModel3D.Material>
  </GeometryModel3D>
</Model3DGroup>

The Brush property can be any old System.Windows.Media.Brush. And as for that Geometry? Well, there are squares:

1
2
3
4
<MeshGeometry3D x:Key="Square">
                Positions="-1,-1,0  1,-1,0  1,1,0  -1,1,0"
                Normals="0,0,1  0,0,1  0,0,1  0,0,1"
                TriangleIndices="0 1 2 0 2 3"/>

isosceles triangles:

1
2
3
4
<MeshGeometry3D x:Key="IsoscelesTriangle">
                Positions="-1,-1,0  1,-1,0  0,1,0"
                Normals="0,0,1  0,0,1  0,0,1"
                TriangleIndices="0 1 2"/>

Coming up with these little nuggets of numbers is the topic of another post. But for now, some sample code:

ThreeDee.png

Featuring basic hit-detection and a bit of interactivity (you can drag a square to increase/decrease the space between boxes, and change the angle of rotation). It’s pure WPF (no unsafe code or interop), it’s 2D, and it’s fast.

ThreeDee.zip

—DKT

Sorry the code formatting is off…the iPhone WordPress client totally destroyed it. I’ll fix it soonish.

Uniqueness of Simple Demographics in the U.S. Population [Link]

Sometimes, math and statistics makes me sad:

“It was found that 87% (216 million of 248 million) of the population in the United States had reported characteristics that likely made them unique based only on {5-digit ZIP, gender, date of birth}. About half of the U.S. population (132 million of 248 million or 53%) are likely to be uniquely identified by only {place, gender, date of birth}, where place is basically the city, town, or municipality in which the person resides. And even at the county level, {county, gender, date of birth} are likely to uniquely identify 18% of the U.S. population. In general, few characteristics are needed to uniquely identify a person.”

It’s quite terrifying to know that such a birthdate, a zip code, and a gender could potentially pass as a unique identifier for someone with the vast and overreaching “anonymized” databases that exist out there.


http://privacy.cs.cmu.edu/dataprivacy/papers/LIDAP-WP4abstract.html

http://arstechnica.com/tech-policy/news/2009/09/your-secrets-live-online-in-databases-of-ruin.ars

—DKT

Building Custom Abstract Data Models in .NET

One of the easiest things to do in .NET is take either a list of vanilla C# objects or the contents of a System.Data.DataTable and show it in a grid through some kind of data binding. It was possible in the WinForms days with the System.Windows.Forms.DataGridView or a vendor-supplied grid (Syncfusion, Infragistics, etc.). It is still very much possible in WPF with the WPF Toolkit grid and any number of (and ChartFX gets special kudos for being able to “figure out” which columns/series are important and graph them by default).

But what if DataTables aren’t your thing, but vanilla C# objects aren’t “dynamic” enough for you? What if you need custom on-the-fly columns but don’t/can’t deal with the headaches of ADO.NET?

(You can skip straight to the Quick How-To if you’d like.)

Using Reflection to build a dynamic grid (don’t do this)

Let’s step back for a bit and consider the vanilla C# object case. Let’s say I wanted to render a list of these objects without using the automagic abilities that seem to be provided in every grid:

1
2
3
4
5
public class Order
{
    public string Symbol { get; }
    public long Quantity { get; }
}

A first stab at this might be to use the Reflection API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class OrderGrid : UserControl
{
    private void InitializeCustomProperties()
    {
        PropertyInfo[] properties = typeof(Order).GetProperties();
 
        // start the awful vendor-specific binding between the
        // reflection pieces and the grid
        foreach (PropertyInfo pi in properties)
        {
            myGrid.Columns.Add(pi.Name);
        }
    }
 
    private void _myGrid_CellValueRequired(object sender, MyGridCellEventArgs e)
    {
        string columnName = myGrid.Columns[e.ColumnIndex];
        PropertyInfo[] properties = typeof(Order).GetProperties();
        PropertyInfo pi = Array.Find(properties, p => p.Name == columnName);
        if (pi == null) return;
 
        var orders = (List<Order>)myGrid.ItemsSource;
        Order order = orders[e.RowIndex];
 
        // now read the actual property value
        e.Value = pi.GetValue(order);
        e.Handled = true;
    }
}

Seems simple and harmless enough, right? Now let’s layer on a slight air of dynamic data—something that seemingly necessitates a reflection-based solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class Order
{
    public string Symbol { get; }
    public long Quantity { get; }
    public IList ExtendedAttributes { get; }
}
 
public class OrderGrid : UserControl
{
    private void InitializeCustomProperties()
    {
        PropertyInfo[] properties = typeof(Order).GetProperties();
 
        // start the awful vendor-specific binding between the
        // reflection pieces and the grid
        foreach (PropertyInfo pi in properties)
        {
            if (pi.Name != "ExtendedAttributes")
            {
                myGrid.Columns.Add(pi.Name);
            }
        }
    }
 
    private void _myGrid_CellValueRequired(object sender, MyGridCellEventArgs e)
    {
        PropertyInfo[] properties = typeof(Order).GetProperties();
 
        // only the first n - 1 columns represent reflection properties;
        // the last few columns come from ExtendedAttributes
        if (e.ColumnIndex < (properties.Length - 1))
        {
            string columnName = myGrid.Columns[e.ColumnIndex];
            PropertyInfo pi = Array.Find(properties, p => p.Name == columnName);
            if (pi == null) return;
 
            var orders = (List<Order>)myGrid.ItemsSource;
            Order order = orders[e.RowIndex];
 
            // now read the actual property value
            e.Value = pi.GetValue(order);
            e.Handled = true;
        }
        else
        {
            e.Value = (e.ColumnIndex - (properties.Length - 1));
            e.Handled = true;
        }
    }
}

It’s starting to get a little nastier now—as the Order class grows and its “ExtendedAttributes” properties get more complex, we end up doing more and more in the view to render this complex object properly—there is no metadata and no reflecting over “ExtendedAttributes”. We don’t know name or type information at the very least, and we certainly can’t decorate the items of the list with an Attribute like we could with a “real” C# property. There is no assurance that every Order’s ExtendedAttributes properties will behave the same way—we’re naïvely using index positioning to uniquely identify a property; what if my Order objects are coming from all over the place?

And how do DataTables always render so well? How does every grid under the sun know how to properly pull schema information from a DataTable using specific properties like DataTable.Columns and the appropriate accessors on every individual row? Does it really just boil down to this:

1
2
3
4
5
6
7
8
if (source.GetType() == typeof(DataTable))
{
    // DataTable specific code
}
else
{
    // a pile of ugly Reflection code 
}

And then what about the Windows Forms Designer? There are all sorts of properties that don’t show up, or show up with slightly different names, or slightly different characteristics than what one would expect through only reflection. Is there more switch/case hackery at work here?

The looks-like-a-DataTable-but-isn’t Approach (better)

It turns out that this problem is already solved, partially because of the original Windows Forms Designer, and partially because of DataTables. A rich API exists for allowing objects to describe themselves, and for lists of objects to publish information about their contents, even if the list is empty. System.Data.DataTable implements several interfaces, but the most important one for purposes of our discussion is
System.ComponentModel.IListSource, which contains an interesting method:

  • GetList: Returns an IList that can be bound to a data source from an object that does not implement an IList itself.

On DataTable, this returns an instance of DataView, which according to the documentation, “Represents a databindable, customized view of a DataTable for sorting, filtering, searching, editing, and navigation.” It turns out that a DataView is what is typically rendered by a grid. We can think of it as a a IList of DataRow objects (it’s actually a list of DataRowView, but that’s not terribly important here), which structurally, is much more similar to a list of boring C# objects.

There are a few other important interfaces that DataView implements other than IList (and ICollection and IEnumerable): ITypedList to provide schema information on the constituent rows (especially when the list is empty, because then we can’t ask the rows themselves) and IBindingList, which allows views to control sorting and filtering.

It turns out that if you implement a few of these key interfaces, you get all this magic for free, too.

The Quick How-To

  1. (Optional) Implement System.ComponentModel.IListSource on your “main” data class—you’d only need to do this if you didn’t want your main class to directly represent your “list” of data.
  2. Create a list class. It should provide implementation for a few interfaces:
    • System.ComponentModel.ITypedList.
      Your implementation of ITypedList.GetItemProperties(PropertyDescriptor[]) should return a PropertyDescriptorCollection that contains the “properties” of the rows of your data set. This interface is required when your list is empty so that a way of providing object metadata exists without resorting to querying the contents of the list.
    • System.Collections.IList.
      This is a hard requirement. Dealing with generic types generically is usually not straightforward and can sometimes require reflection; even to this day, a lot of code in WPF looks for (and makes use of) this interface.
    • System.Collections.Generics.IList<T>.
      I haven’t seen too much in the way of generic components requiring an implementation of this interface, but it’s a good idea to implement regardless—it’ll be easier to work with LINQ and other APIs that expect generic collections.
    • System.Collections.Specialized.INotifyCollectionChanged (optional).
      This is the same interface that classes like ObservableCollection<T> use to propagate their contents changes in WPF. (If you need Windows Forms support, you’ll have to instead implement…)
    • System.ComponentModel.IBindingList (optional).
      Implement this interface only if you need backwards compatibility with Windows Forms. It’s a bit of a hybrid interface, incorporating aspects of both ICollection and ICollectionView, but as a result of that, you’ll effectively limit clients to one view on your collection.
  3. (Optionally) Implement System.ComponentModel.ICustomTypeDescriptor on your “row” data class. I usually implement this by having each of my “rows” retain a reference to the “list”, and merely calling ITypedList.GetItemProperties(PropertyDescriptor[]) on the list. Implementing something once takes less time than implementing something twice.

    I like to implement ICustomTypeDescriptor on the row because it provides a context-insensitive way of retrieving properties of the row. If someone created a System.Collections.Generic.List<T> containing my “rows”, this list is still eligible for rendering in a grid without any additional work (except, of course, when the list is empty, because then there would be no way of providing schema information).

  4. Create a subclass of System.ComponentModel.PropertyDescriptor (read this if you don’t know what this class is for) for each property that you want your rows to have. You will want/need to implement a few important properties and methods:
    • public Type PropertyType { get; } (override required)
      The type of the property. If you want the type of values contained in the column to be completely wide open, then return typeof(object).
    • public TypeConverter Converter { get; } (override optionally)
      The converter that is used in conjunction with the property. For real properties, this would be defined through the usage of a [System.ComponentModel.TypeConverterAttribute] attribute on the property’s type or the property itself.
    • public Type ComponentType { get; } (override required)
      The type that defines the property. This is essentially your “row” class.
    • public object GetValue(object component); (override required)
      This is probably the most important method; this is the method that tells the system how to fetch a value from your row for the “property”.
    • public void SetValue(object component, object value); (override required)
      You can override this to set the value of this property on your row; otherwise, you can throw NotSupportedException if you want.
    • public bool IsReadOnly { get; } (override required)
      Return true or false, depending on whether or not the property should be publicly modifiable.
    • public bool CanResetValue(object component); (override required)
      When you’re using the Windows Forms Designer, this is the method that determines whether or not you can “reset” the value of the property to some default value. Other visualizers could make use of it too, but I haven’t seen too many that take advantage of it.
    • public void ResetValue(object component); (override required)
      This actually implements the resetting of a value as mentioned above. Either implement it or throw NotSupportedException.
    • public bool ShouldSerializeValue(object component); (override required)
      The Windows Forms Designer uses this method to determine whether or not a property’s value should be serialized. If a property was set to its default value, this method would return false because there would be no reason to actually persist the value of the property (since reapplying it wouldn’t result in a change).

The Quick Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/// <summary>
/// The class that serves as the "entry point" for your data model.
/// </summary>
/// <remarks>
/// It's not always necessary to create a class like this, but it can be
/// helpful from a design standpoint. Here, like the DataTable, I expose
/// a collection of "columns" that client APIs can use for their own
/// purposes.
/// </remarks>
public class MyDataTable : IListSource
{
    private readonly MyDataRowCollection _dataRows;
    private readonly PropertyDescriptorCollection _properties;
 
    public MyDataTable(...)
    {
        _dataRows = new MyDataRowCollection(rows, columns);
        _properties = columns;
    }
 
    public MyDataRowCollection Rows { get { return _dataRows; } }
 
    public PropertyDescriptorCollection Columns { get { return _properties; } }
 
    /// <summary>
    /// Returns the underlying collection of elements for this source.
    /// </summary>
    /// <remarks>
    /// It is somewhat rare to see this implemented any other way than through
    /// an explicit implementation because you will generally want to
    /// expose a specific collection type to expose more advanced behavior.
 
    /// (We do the same here through the <see cref="Rows"/> property.
    /// </remarks>
    System.Collections.IList IListSource.GetList()
    {
        return _dataRows;
    }
 
    bool IListSource.ContainsListCollection
    {
        get { return false; }
    }
}
 
/// <summary>
/// The class that directly represents a collection of rows.
/// </summary>
/// <remarks>
/// You can either implement IList<T>/IList manually, or inherit from another
/// collection implementation. However, your particular use case will probably
/// only need or want to expose a subset of the functionality of those interfaces,
/// so it may be beneficial to implement the interfaces directly and hide some
/// collection methods through explicit implementation.
/// </remarks>
public class MyDataRowCollection
    : ITypedList, ReadOnlyCollection<MyDataRow>,
        IList<MyDataRow>, IList
{
    private readonly MyDataTable _parent;
 
    public MyDataRowCollection(MyDataTable parent, IList<MyDataRow> rows)
        : base(rows)
    {
        _parent = parent;
    }
 
    public MyDataTable ParentTable { get { return _parent; } }
 
    PropertyDescriptorCollection ITypedList.GetItemProperties(
            PropertyDescriptor[] listAccessors)
    {
        return _parent.Columns;
    }
 
    string ITypedList.GetListName(PropertyDescriptor[] listAccessors)
    {
        return null;
    }
}
 
/// <summary>
/// The class that represents the data in a "row".
/// </summary>
public class MyDataRow : ICustomTypeDescriptor
{
    private readonly MyDataRowCollection _parentCollection;
    private readonly object[] _rows;
 
    internal MyDataRow(MyDataRowCollection parentCollection)
    {
        _parentCollection = parentCollection;
    }
 
    public object this[string name]
    {
        get { return _rows[ColumnIndexFromName(name)]; }
        set { _rows[ColumnIndexFromName(name)] = value; }
    }
 
    private int ColumnIndexFromName(string name)
    {
        PropertyDescriptor pd = _parentCollection.ParentTable.Columns[name];
        if (pd != null)
        {
            return _parentCollection.ParentTable.Columns.IndexOf(pd);
        }
        return -1;
    }
 
    AttributeCollection ICustomTypeDescriptor.GetAttributes()
    {
        return AttributeCollection.Empty;
    }
 
    string ICustomTypeDescriptor.GetClassName()
    {
        return typeof(MyDataRow).FullName;
    }
 
    string ICustomTypeDescriptor.GetComponentName()
    {
        return typeof(MyDataRow).Name;
    }
 
    TypeConverter ICustomTypeDescriptor.GetConverter()
    {
        return null;
    }
 
    EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
    {
        return null;
    }
 
    PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
    {
        return null;
    }
 
    object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
    {
        return null;
    }
 
    EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
    {
        return EventDescriptorCollection.Empty;
    }
 
    EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
    {
        return EventDescriptorCollection.Empty;
    }
 
    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
    {
        return ((ITypedList)_parentCollection).GetItemProperties(null);
    }
 
    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        return ((ITypedList)_parentCollection).GetItemProperties(null);
    }
 
    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }
}
 
/// <summary>
/// The class that represents information about a "column".
/// </summary>
public class MyDataColumn : PropertyDescriptor
{
    private readonly Type _propertyType;
 
    public MyDataColumn(string name, Type type, Attribute[] attrs) : base(name, attrs)
    {
        _propertyType = type;
    }
 
    public override object GetValue(object component)
    {
        return ((MyDataRow)component)[this.Name];
    }
 
    public override void SetValue(object component, object value)
    {
        ((MyDataRow)component)[this.Name] = value;
    }
 
    public override bool IsReadOnly
    {
        get { return false; }
    }
 
    public override Type PropertyType
    {
        get { return _propertyType; }
    }
 
    public override Type ComponentType
    {
        get { return typeof(MyDataRow); }
    }
 
    public override void ResetValue(object component)
    {
        throw new NotSupportedException();
    }
 
    public override bool CanResetValue(object component)
    {
        return false;
    }
 
    public override bool ShouldSerializeValue(object component)
    {
        return false;
    }
}

Now Use It

There is a lot that got glossed over here, but it’s a very deep subject. It amazes me how few .NET developers know about and make use of this layer (either by consuming objects in this fashion or by publishing objects that conform to this API), especially because there is so much buy-in from third-party vendors and projects, and especially because this is one of the few components of the binding API that has not had to change much at all between Windows Forms and WPF.

If you are working on an infrastructure project of any kind that purports to expose data to a .NET GUI (Windows Forms or WPF), absolutely make use of this in order to keep both your view and your data model as flexible and independent as possible; you’ll be happy you did. —DKT

Of Magic and Properties in C# (and why Reflection isn’t the answer)

Reflection can be used to discover information about classes at runtime. And of course, you can use the Reflection API to cause all kinds of magic. You could iterate through a bunch of objects and output all of their property values. Or you could increment all the numeric properties by one. Or find all the properties tagged as [Bold] and draw them on the screen in a grid in a funny way. Or write each property-change value to a log file.

Considering the following class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class Order : DependencyObject, INotifyPropertyChanged
{
    public static readonly DependencyProperty SymbolProperty =
        DependencyProperty.Register(
            "Symbol", typeof(string), typeof(Order),
            new PropertyMetadata(null));
 
    private double _quantity;
    private OrderSide _side;
 
    public Order()
    {
        _quantity = 100.0;
    }
 
    public string Symbol
    {
        get { return (string)GetValue(SymbolProperty); }
        set { SetValue(SymbolProperty, value); }
    }
 
    [DefaultValue(100.0)]
    public double Quantity
    {
        get { return _quantity; }<br>
        set
        {
            if (_quantity != value)
            {
                _quantity = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Quantity"));
            }
        }
    }
 
    [TypeConverter(typeof(OrderSideConverter))]
    public OrderSide Side
    {
        get { return _side; }
        set
        {
            if (_side != value)
            {
                _side = value;
                if (SideChanged != null)
                {
                    SideChanged(this, EventArgs.Empty);
                }
            }
        }
    }
 
    public event EventHandler SideChanged;
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }
}

We could easily figure out how to abstractly interact with a class like this…right?

What, really, is a property?

I suppose you could say it’s just a list of optional attributes, optional modifiers, a type, a property name, and a getter, setter, or both. But much as we argue to our Java counterparts that a property is more than a simple wrapping of a get() and set() method, a full-fledged property is a bit more than its individual curly braces and access modifiers. One of the biggest aspects of a real property is change notification, which is never actually part of the property declaration*. And judging from the pathological Order class that started the post, there are a lot of ways to skin that notifying cat. And I haven’t even mentioned the “fake” properties in things like a System.Data.DataTable, where the Reflection API is of no real use at all.

At a minimum, really, a property is a field that is:

  • observable
  • gettable, and optionally settable (fields that are settable and not gettable are weird and we won’t talk about them any more)
  • otherwise describable through custom attributes that provide additional metadata

More than just a “property”, and definitely more than what you get back when you reflect over a type and pull out all of its System.Reflection.PropertyInfos. And, again, reflecting over a DataTable tells you nothing about schema information at all.

If only there were a way of describing a property…

…oh wait, there is. There’s the System.ComponentModel.PropertyDescriptor class:

Although it may seem redundant to have two classes to describe properties, this isn’t quite the same information as can be retrieved through reflection. There is less emphasis on being an object model for compiled code and more emphasis on providing tools for abstractly working with properties—for example, there is no concept of access levels (if you’re holding an instance of PropertyDescriptor, it might as well be public). Some concepts exposed as Attributes become first-level concepts in this API (BrowsableAttribute, DisplayNameAttribute, TypeConverterAttribute become IsBrowsable, DisplayName, and Converter, for example). There is also a linkage to the event model that provides change notifications through AddValueChanged and RemoveValueChanged.

You could probably picture being able to build a generic grid based on nothing more than a list of objects and a list of PropertyDescriptors about them; in fact, that’s exactly what any grid worth its .NET salt does—from interacting with POCOs to DataTables. And a good portion of this API was driven by the requirements of the original Windows Forms Designer, one of the most “abstract” views of all.

To get a list of PropertyDescriptors, call one of the overloads of TypeDescriptor.GetProperties. You always get back an appropriate PropertyDescriptor for the “type” of the property—dependency properties give you back instances of DependencyPropertyDescriptor, and internal subclasses of PropertyDescriptors are returned for other properties (and they’ll properly take into account implementations of the INotifyPropertyChanged interface). In fact, one of the common methods for listening for changes in dependency properties is really just taking advantage of the fact that the PropertyDescriptor API provides a way for arbitrary clients to listen for changes in property values whereas DependencyProperty does not.

This is also the appropriate API that you should use when working with object models abstractly. Reflection isn’t going to always provide you all of the information you need, and you have a lot more to self-assemble. Reflection is also the slowest of all possibilities. Although much of the work done through PropertyDescriptors uses reflection under the hood, it doesn’t necessarily need to: interacting with DependencyProperty through this API requires no reflection, and calling DependencyPropertyDescriptor.GetValue(object) is a heck of a lot faster than calling the corresponding PropertyInfo.GetValue(object).

PropertyDescriptor is also a facet of the appropriate API when building an abstract data model—a model where the properties are not known at compile-time and instead drive controls at run-time. Building views that work off of this abstract data model have been done to death and there is almost never a reason to build your own any more**. Instead, next time I’ll cover the road less-travelled, your very own abstract data model. —DKT

*It’s actually a bit of a shame that the property syntax doesn’t support a built-in event that is every much as part of the property declaration as the getter and setter. Part of what makes a PropertyDescriptor necessary is exactly that the property definition isn’t the one-stop shop for everything property-related.

**Off the top of my head, System.Windows.Forms.DataGridView, Syncfusion, Infragistics support binding in Windows Forms, the WPF Toolkit grid for WPF, and ChartFX does an admirable WPF-y job for your charting needs.