Tag Archives: Silverlight

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 , , ,
Advertisements