Archives for: February 2005, 04

04/02/05

Permalink 02:17:22 pm
Categories: Programming, .NET

Simulating object properties with ITypedList and custom PropertyDescriptors

In newsgroup post in the Developer Express support newsgroup for their XPO product, I was recently asked if it was possible to show information that's really stored in a one-to-many relationship as additional columns on the main object. Actually, .NET makes this possible using an implementation of the ITypedList interface together with a custom property descriptor - in this way, arbitrary additional properties on an object can be "simulated", regardless of the real source of the data.

First, let me explain the problem in the sample case (a download link is at the bottom of the post) a little further. Let's assume you have a class (MasterRecord) that stores a collection of detail values (DetailValue) objects in a typed collection. The following diagram shows the structure, just as an overview of the classes involved:

MasterRecord UML

Now, for presentation purposes, the data is to be represented in a grid. But the user doesn't want to have a long hierarchical structure where all the detail values are listed underneath the corresponding master record. Instead, the detail values are supposed to be represented by additional columns in the grid row of the master record. Or maybe you know exactly which detail values (with which names, in this example) will be there, so you actually know which and how many columns you will need.

Consider you have the following data:

  • MasterRecord: "TestRecord1"

    • DetailValue: Name: "TheAnswer", Value: 42
    • DetailValue: Name: "TestRecord1Value", Value: 101
  • MasterRecord: "Another test record"

    • DetailValue: Name: "TheAnswer", Value: 52
    • DetailValue: Name: "another value", Value: 824

This data should result in a grid view like this:

MasterRecordTheAnswerTestRecord1Valueanother value
TestRecord142101 
Another test record52 824

The custom property descriptor

The custom property descriptor is the first step of the implementation. The concept behind property descriptors is simple: Every time a property of an object is accessed by the .NET data binding mechanisms, a property descriptor for that property is used. The property descriptor is the class that has the real knowledge of how exactly the data for the property is to be accessed. This is true for every bound property, even the "normal" ones, for these a ReflectionPropertyDescriptor is used internally.

Now say we have created a property descriptor instance for the property called "TheAnswer" from the example. What a property descriptor would have to do to get the value for this "virtual" property from a MasterRecord instance is this:

  1. Iterate over the MasterRecord's detail values collection and see if there's an entry called "TheAnswer".
  2. If such an entry is found, return its value.
  3. If such an entry is not found, possibly return some kind of placeholder for an "empty value".

Here's the code from the sample property descriptor that does just that:

public override object GetValue(object component) {
  MasterRecord mr = (MasterRecord) component;

  foreach(DetailValue dv in mr.DetailValues)
    if (dv.Name == this.Name)
      return dv.Value;

  return 0;
}

Obviously, the descriptor could get the needed value from any arbitrary source instead of from the detail value collection. For example, I have used a property descriptor in a project that would get values from specific interfaces if the object implemented it, falling back to defaults if it didn't. If you've ever had the problem that a collection typed for a base class would always show only the properties of the base class in data binding, this is the solution: Just create a property descriptor that will check for the real type of the given object and return properties from derived types if necessary. Note, though: as you'll see in the next paragraph, all objects in a collection are still expected to have the same set of properties (what would the grid look like if that wasn't a requirement?), so your descriptor must be able to deal with objects that don't have the expected data.

Implementing ITypedList

The second part of the implementation is the ITypedList implementation. This is the point where we tell the binding mechanisms which properties it should access for our given collection. It's an important fact that this interface is implemented on the collection: all objects in the collection are expected to have the same set of properties.

The interesting method of that interface is the GetItemProperties method, which returns a PropertyDescriptorCollection. In many cases, I've found that it makes sense to calculate the set of property descriptors once (or at least at some specific point) and store it in a static variable for the collection type, unless there are reasons to want to recalculate it every time it's being queried. This is the method from the sample that does the calculation:

public void CalculatePropertyDescriptors() {
  PropertyDescriptorCollection origProperties = 
    TypeDescriptor.GetProperties(typeof(MasterRecord));
  ArrayList properties = new ArrayList();

  foreach(PropertyDescriptor desc in origProperties)
    if (!typeof(ICollection).IsAssignableFrom(desc.PropertyType))
      properties.Add(desc);

  ArrayList handledNames = new ArrayList();

  foreach(MasterRecord mr in this)
    foreach(DetailValue dv in mr.DetailValues)
      if (!handledNames.Contains(dv.Name)) {
        properties.Add(new DetailValuePropertyDescriptor(dv.Name));
        handledNames.Add(dv.Name);
      }

  propertyDescriptors = new PropertyDescriptorCollection((PropertyDescriptor[]) 
    properties.ToArray(typeof(PropertyDescriptor)));
}

There are mainly two things happening here, the whole process blurred a bit by the handling code needed for the PropertyDescriptorCollection:

  1. After getting the default property descriptors for a MasterRecord type object, they are filtered while being transferred into our own temporary array. Descriptors for collection types are left out because we don't want to show the field for the collection in the grid. This is of course an optional step.
  2. For every unique name of a detail value in any of our master records, one instance of our own custom property descriptor is created and also added to the temporary array. This step establishes the "virtual" properties, together with their names, for which our code will be called automatically.

The result

Data is initialized in the sample with the following code, the descriptors calculated and the datasource bound:

MasterRecordCollection coll = new MasterRecordCollection();
MasterRecord mr = new MasterRecord("TestRecord 1");
mr.DetailValues.Add(new DetailValue("TheAnswer", 42));
mr.DetailValues.Add(new DetailValue("TestRecord1Value", 101));
coll.Add(mr);

mr = new MasterRecord("Another test record");
mr.DetailValues.Add(new DetailValue("TheAnswer", 52));
mr.DetailValues.Add(new DetailValue("another Value", 824));
coll.Add(mr);

coll.CalculatePropertyDescriptors();
dataGrid1.DataSource = coll;

This results in the following output:

The result
Download

The sample that has been mentioned in this post can be downloaded here. 

Permalink 10:49:38 am
Categories: General, Programming

Blogging C# code

While I was trying what the best way would be to include C# code in my blog, I found that WordPress has problems with <pre> tags: it inserts <br> and <p> tags all over the place, trying to preserve XHTML validity. While I do like the validity idea, I don't like the fact that it becomes more or less impossible to use the <pre> tag to publish code.

Looking around, I found the two modules that I need to get back proper <pre> functionality and a little nice highlighting for C#: the Syntax Highlighting with Enscript in WordPress plugin and a highlighting definition file for GNU enscript. These are easy to install together and render results like this (GPL code borrowed from the Linux kernel, drivers/hotplug/cpqphp_core.c):

static inline int is_slot66mhz (struct slot *slot)
{
        if (!slot || !slot->p_sm_slot)
                return 0;

        if (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E)
                return 1;

        return 0;
}

or this in C#:

  bool result;
  Transaction transaction = StorageObject.BeginTransaction( );
  try {
    route.CurrentTransaction = transaction;
    result = route.CalculateElements( );

    if (result)
      transaction.Commit( );
    else
      transaction.Rollback( ); // no elements
  }
  catch {
    transaction.Rollback( );
    throw;
  }

  return result;
Permalink 09:29:52 am
Categories: General

SMS to Skype

Connectotel has introduced a service (currently in beta test) where mobile phones can be used to send messages to Skype users. If you use Skype and you want to be able to receive messages sent to you by SMS, all you have to do is add a pseudo user to your contact list.

In short, this is what you do:

  • Register a Skype contact called "smsgateway".
  • Send an SMS message with your mobile phone to the number +447747782320, formatted like this:




       skype johndoe This is a message to johndoe


    Where "johndoe" would be the Skype name of the recipient, of course.
  • Wait a few seconds...

Of course you can optionally store that number in your phonebook if you want to use it more often.

The original instructions can be found here.

Enter your email address:

Search