Databinding a WPF control to something else than a static property

Posted by Chris on February 21, 2007

A couple of days ago I was trying to solve a problem with databinding in WPF. What I was trying to do was to create columns for a ListView (with a GridView set for it’s view). Creating columns was no problem, neither was binding the columns to some property of the objects in the list that was set as the ItemsSource of the ListView. The problem was however that the “properties” that I wanted to bind the columns to was not really properties (in the C#/.NET vocabulary).

To create a binding on a normal statically declared property, code like the below would work:

Binding binding = new Binding();
binding.Path = new PropertyPath("SomeProperty");
binding.Mode = BindingMode.OneWay;

FrameworkElementFactory textElement = new FrameworkElementFactory(typeof(TextBlock));
textElement.SetBinding(TextBlock.TextProperty, binding);

DataTemplate template = new DataTemplate();
template.VisualTree = textElement;

GridViewColumn column = new GridViewColumn();
column.CellTemplate = template;

With this code in place I now have a column containing a single textblock. The Text property of that textblock will contain the value of the property SomeProperty for each object in the collection that is set as the ItemsSource of the listview. However, as I mentioned above, the problem was that my object (or rather, the object’s type) did not have a static property called SomeProperty. Instead it has a property called Properties, which is a Dictionary containing a “dynamic” set of objects each representing some property (in the general meaning of the word, not in the C#/.NET vocabulary) of the object I am showing on the current row of the listview.

public class ShownInList {
  ...

  public Dictionary Properties {
    ...
  }
}

public class PropertyObject {
  ...

  public string Name {
    ...
  }

  public object Value {
    ...
  }
}

As seen above, each property has a name and a value. What I now want to do is to create a column and bind it to a property with a specific name, so that it will show the value of that property. The intuitive thing to try was to create the binding with a PropertyPath initialized with a string such as “Properties['SomeProperty']“. This did not work however, and neither did the different ways I tested to write the property path string.

Some Googling later I found the solution. Instead of binding to a property using a PropertyPath I could skip setting up the path at all and instead use a custom converter. Here is what I did:

Binding binding = new Binding();
binding.Converter = new PropertyObjectConverter();
binding.ConverterParameter = "SomeProperty";
binding.Mode = BindingMode.OneWay;

...

public class PropertyObjectConverter : IValueConverter {
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
      ShownInList obj = (ShownInList)value;

      string key = (string)parameter;
      return obj.Properties.ContainsKey(key) ?
        obj.Properties[key].Value :
        null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
      throw new NotImplementedException();
    }
}

The binding is set up to call a converter to get a value to show. The converter is called with the object, of type ShownInList, that is the source for the current row, and a parameter describing which property in the dictionary I want to bind to. If the dictionary contains a propertyobject with the name as key then it returns the Value property of that object, otherwise it returns null.

If anyone has a better solution than mine then please add a comment about it.

Trackbacks

Trackbacks are closed.

  • raisa

    please, i need your help...can you send me all the code of this example

blog comments powered by Disqus