views:

21

answers:

0

I'm running into some very anomalous behaviors that I'm having some trouble understanding. Basically, I've redone Colin Eberhardt's MultiBinding technique as a behavior (System.Windows.Interactivity) - mostly because I have a lot of other behaviors and this results in cleaner xaml. Along the way I tried to figure out why the ContentProperty attribute is being glitchy. I can repost my multibinding behavior if there is interest, but for the most part it's off-topic.

Here is a snippet Colin's original (minus a custom collection) implementation of the MultiBinding object:

public class MultiBindingCollection : ObservableCollection<MultiBinding> {}

[ContentProperty("Bindings")]
public class MultiBindings : FrameworkElement {
    ...
    public MultiBindingCollection Bindings { get; set; }
    ...

In Silverlight 3, because the ContentProperty is set the object can be used like this:

<local:MultiBinding TargetProperty="Text" Converter="{StaticResource TitleConverter}">
    <Binding Path="Surname"/>                            
    <Binding Path="Forename"/>
</local:MultiBinding>

In Silverlight 4 this doesn't work so well. What frustrates me is that it's not clear what's going on. With only one or two child bindings it almost always works ok. But when more are added (number is variable, but usually 5 or more will break) at runtime a xamlparse exception gets thrown with [Line: 0 Position: 0] message, probably the least helpful exception ever. Simply wrapping the children in a collection will make it work, but the syntax gets a bit messy.

<local:MultiBinding TargetProperty="Text" Converter="{StaticResource TitleConverter}">
    <local:MultiBinding.Bindings>
        <local:BindingCollection>
            <Binding Path="Surname"/>                            
            <Binding Path="Forename"/>
        </local:BindingCollection>
    </local:MultiBinding.Bindings>
</local:MultiBinding>

The fact that it's not a standard "direct content" error, and that it works for a certain number of bindings but not others are really perplexing. As I was making my behavior I ran into the same issue, and came up with a different workaround. It seems that as long as the children aren't of type Binding the ContentProperty works just fine - and the fix is to simply use a container class for the binding. So the relevant parts of the behavior look like this:

[ContentProperty("Bindings")]
public class MultiBinding : Behavior<FrameworkElement> {
    ...
    public BindingCollection Bindings { get; set; }
    ...
}

public class BindingCollection : ObservableCollection<BindingWrapper> { }

public class BindingWrapper {
    public System.Windows.Data.Binding Binding { get; set; }
}

Set up like that the behavior can be used normally with children getting tossed into the Bindings collection, like so.

<Path StrokeThickness="2" Stroke="Black" x:Name="ConnectorPath">
    <Interactivity:Interaction.Behaviors>
         <Behaviors:MultiBinding TargetProperty="Data" Converter="{StaticResource LineConverter}">
             <Behaviors:BindingWrapper Binding="{Binding}" />
             <Behaviors:BindingWrapper Binding="{Binding SourceItem.Transform}" />
             <Behaviors:BindingWrapper Binding="{Binding SourceItem.Top}" />
             <Behaviors:BindingWrapper Binding="{Binding SourceItem.Left}" />
             <Behaviors:BindingWrapper Binding="{Binding SourceItem.Width}" />
             <Behaviors:BindingWrapper Binding="{Binding SourceItem.Height}" />
             <Behaviors:BindingWrapper Binding="{Binding SinkItem.Transform}" />
             <Behaviors:BindingWrapper Binding="{Binding SinkItem.Top}" />
             <Behaviors:BindingWrapper Binding="{Binding SinkItem.Left}" />
             <Behaviors:BindingWrapper Binding="{Binding SinkItem.Width}" />
             <Behaviors:BindingWrapper Binding="{Binding SinkItem.Height}" />
         </Behaviors:MultiBinding>
     </Interactivity:Interaction.Behaviors>
 </Path>

Does anyone know what's the issue here? It's not a big deal, but not understanding what's happening tends to drive me up the wall. The documentation for the attribute was not particularly helpful.

Colin's update of his original implementation can be found at http://www.scottlogic.co.uk/blog/colin/2010/05/silverlight-multibinding-solution-for-silverlight-4/