Binding to properties of a custom property in WPF, Silverlight 4 or Windows Phone 7

I was trying to create a UserControl for Windows Phone 7 yesterday and I wanted to enable specifying a  collection-type property that I could configure in my View/XAML file.

I have registered a DependencyProperty, but since I have not done many UserControls or CustomControls in WPF or SL, so I thought I would look how it is done in other similar places – like Grid.ColumnDefinitions. OK, so it is a custom type RowDefinitionCollection based on PresentationFrameworkCollection<RowDefinition>. I thought an ObservableCollection<MyItemType> or a List<> would work, but something did not work right, so I thought derive from PresentationFrameworkCollection<>, but when I tried – it turned out it does not have an accessible parameterless constructor which turned out to be some sort of an issue. I really wanted to make it work, so I thought – OK, I will implement my own version, so I created my collection type as a wrapper around an ObservableCollection, that derives from a FrameworkElement (I played with DependencyObject too) and implements all these interfaces – ICollection, ICollection<>, IList, IList<>, IEnumerable, IEnumerable<>.

All was good – I defined MyItemType as deriving from a FrameworkElement too and added some properties, among others an ICommand-typed-Command and CommandParameter. All hell broke loose when I tried to bind to the Command in XAML.

I kept getting these XamlParseException AG_E_PARSER_BAD_PROPERTY_VALUE on the line that had the binding to the Command. I tried looking at this from all angles of Google and Bing and could not find the right solution, until I tried the below and got the same problem!

<Grid>
    <Slider
        x:Name="slider"
        VerticalAlignment="Top"
        HorizontalAlignment="Stretch"
        Minimum="0"
        Maximum="100" />

    <Grid
        VerticalAlignment="Bottom"
        HorizontalAlignment="Stretch"
        Height="100">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="{Binding Value, ElementName=slider}"/>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
 
        <Rectangle
            Fill="Red"
            Grid.Column="0"
            VerticalAlignment="Stretch"
            HorizontalAlignment="Stretch" />
    </Grid>
</Grid>

OK, so it seems like binding on ColumnDefinitions is not supported on WP7 either. Tried the same snippet in WPF – worked great. Silverlight 4 – no exception, but it just would not update my rectangle. So it seems like Silverlight is limited in that regard.

That was close – I started looking into it more and found that it would almost work, but the DataContext on my collection would not get updated whatever I do. Finally – I found two things I needed to do:

  • Handle DataContext changes on my UserControl and update the DataContext on my collection and do the same from the collection to MyItemType. Only thing – there is no DataContextChanged event. Sheesh… Fortunately we have our MVPs to the rescue – I found a solution on CodeProject quite easily – http://www.codeproject.com/Articles/38559/Silverlight-DataContext-Changed-Event.aspx – just added IDataContextChangedHandler to both the control and the collection and update the DataContext on their properties.
  • Made sure that MyItemsProperty DependencyProperty registration does not specify the default value as “new MyItemsCollection(MyUserControl)”, but rather do it in the constructor – otherwise all instances of the control would share the same collection! This is said to cause problems when applying styles to controls, since setting the value on the control overrides anything being set by the style, but I will not be bothered by it, since the control implementation isn’t lookless or re-template-able anyway.

It works!

Advertisements
Tagged , , ,

2 thoughts on “Binding to properties of a custom property in WPF, Silverlight 4 or Windows Phone 7

  1. xyzzer says:

    Note to self – need to find a better Live Writer plugin for source code formatting.
    I can work on a sample I could publish if anyone is interested.

  2. xyzzer says:

    Note – a better solution than this might be to simply bind the DataContext of a DependencyObject-typed property to the owning object’s DataContext. It is also useful to check if its DataContext isn’t already set to something to allow for setting a different DataContext of that property in XAML as its DataContext would be set before the owning object’s DataContext. Look for samples in my BindableApplicationBar.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: