Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Adventures While Building a Silverlight Enterprise Application - Part #25

0.00/5 (No votes)
8 Oct 2009 1  
Adventures while building a Silverlight Enterprise Application - Part #25

In the previous episode, I discussed how an enum can be used to encapsulate char values in a database, in this case using a Gender enum as an example. As cool as that was, it does pose a problem with databinding in Silverlight that I'd like to share with you. Part of that explanation leads us into the realm of reflection (that would make for a cool blog title :) ) and then into some cool trick in binding, all to end with a bit of a disappointment. So if you already feel depressed, stop reading now :-P.

The Story

First there was a BussinessObjectBase. This class handles a lot of stuff around transporting data between the service and the client and back. It also helps in keeping track of property changes and notifies about them. It's a very generic class and it serves as a base class for all our 'business' objects.

In this case, let's say there is a PersonBase class, that is derived from BusinessObjectBase. PersonBase is generated based on some metadata, so we don't want to touch this source. The PersonBase class has a property called Gender that is of type string.

Then there is the Person class, which was generated but is meant to be used for custom code, so this is where we will write some code to make our Gender available as a Gender instead of a string.

We could simply write something like this in the Person class:

private char GetGender()
{
string gender = base.Gender;
if (gender.Length == 0)
{
return DefaultGender;
}
return gender[0];
}

public Gender GenderValue
{
get
{
return (Gender)GetGender();
}
set
{
base.Gender = ((char)value).ToString();
}
}

Our intention here is to hide the base implementation of the Gender property and have our own implementation that returns an actual Gender enum. Nothing special so far.

The next step is to use this new property in a databinding scenario. Here is what the binding statement in XAML would look like:

{Binding Path=Gender, Mode=TwoWay}

Now if you'd try to use a binding statement like this and run the code, what would happen is that you would get an AmbiguousMatchException, the reason being that the binding engine can't distinguish between PersonBase.Gender and Person.Gender.

What? But we wanted to hide PersonBase.Gender, right? Absolutely, but both properties are public, so both are actually available.

Reflecting on the 'new' Property

To get a better understanding of why this was happening, I decided to write some reflection code:

object person = newPerson();
object personBase = newPersonBase();

Type personType = person.GetType();
PropertyInfo personGenderProperty = personType.GetProperty("Gender");
MessageBox.Show(personGenderProperty.GetValue(person, null).ToString());

Actually trying to get the value of the Gender property through reflection threw the AmbiguousMatchException, just like it did when databinding to it. Actually calling personType.GetProperties from the Immediate Window in Visual Studio returned both properties. Then the exception all of a sudden makes sense.

What might seem a bit awkward is the fact that both properties are there. If I'd try to write string gender = somePerson.Gender where somePerson is of type Person then it would not compile because I can't implicitly cast this, proving that the base property is actually hidden. Still, having the property available is needed, because the derived class needs to be able to call the property in the base class.

Trying to Bind to it Anyway

Still, I needed to find a way to bind to this property. I came up with some simple solutions:

  1. Make the base property protected
  2. Rename one of the properties to remove the problem all together
  3. Find a way to distinguish between the two properties in databinding

The first solution doesn't work for me, because I can't touch this code (it was generated, remember?).

The second solution would mean that I'd have to rename the property in the derived class, which doesn't seem very nice.

The third solution was a long shot, but I had to give it a try. I did actually find this syntax to use for a case like this, however it wasn't very well documented, so I did some experimentation to get a better understanding of it. I started writing this in XAML:

{Binding Path=(local:Person.Gender)}

This failed with an exception telling me that this was an invalid value for the attribute. I was surprised and puzzled, because I read about other people using it and it is actually in the documentation like this. Some further investigation taught me that this only works on dependency properties. I've built a small example of this and it actually works very well, however...

...having a dependency property with all the plumbing involved is best done by deriving your class from DependencyObject (which contains stuff like GetValue and SetValue). I obviously can't derive Person or PersonBase from DependencyObject, because I have already derived them from another class. This means I now have to rename the property in the derived class :(.

You can find the example of binding to a new property here. Hopefully it is helpful to you. It was a great learning experience overall. Just too bad it didn't lead to a better solution for me.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here