views:

614

answers:

3

We've got a Silverlight application with several listboxes and comboboxes that display data sorted incorrectly, which I need to fix. Most of their ItemSource properties are set through XAML. Their DataContext may not be set directly on the control, and instead were set on a parent. So I can't easily slap an "OrderBy" on the ItemSource or DataContext assignment in the code behind, since that assignment may not explicitly exist.

So I had the idea to create a "proxy" collection. The proxy collection would get the original ItemSource and expose a sorted version. I'd then be able to convert this:

<ListBox ItemsSource="{Binding}"/>

into this:

<ListBox>
    <ListBox.ItemsSource>
        <my:ProxyCollection Source="{Binding}" SortBy="Name"/>
    </ListBox.ItemsSource>
</ListBox>

Not too shabby! But, since the ProxyCollection isn't a child of the ListBox, the ListBox's DataContext isn't propagated to it, and the binding doesn't magically work. If I manually set the ProxyCollection collection's DataContext it works great. But if I have to set the DataContext manually anyways I may as well just remove the proxy collection and manually set the Listbox's DataContext, adding an "OrderBy".

So any ideas on how I can automatically get the ListBox's DataContext set on the proxy collection? Or any other genius ideas?

A: 

Given the data context is being set at the parent, if the list box is bound to a property of a class being set as the data context - that property will be exposed as a get / set and you could deliberately output the data from the property in a sorted manner.

Not ideal, in that in a MVVM type scenario, that would dictate the sort order to very view consuming the VM however.

Andrew
+1  A: 

I've stumbled across a very similar problem. I wanted to cascade parameters from one combobox into a subsequent combobox with the same design goal of no code....

My solution is hardly elegant, but it works of a fashion :)

Basically I have a SharedDataContext control, this has a "Value" DP i bind to the datacontext directly.

I then use an attached property on the shared data context to allow for registration of other elements.

This makes the XAML look like this

<my:SharedDataContext Value="{Binding}" />
<ComboBox>
    <ComboBox.ItemsSource>
       <my:ProxyCollection my:SharedDataContext.Register="1" />    
    </ComboBox.ItemsSource>
</ComboBox>

Inside the SharedDataContext I have a static collection of framework elements.

When the Register attached property is "changed" I catch the PropertyChangedCallback and add the sender (in this case the ProxyCollection instance) to the collection.

When the databinding changes (and hence the Value property of the SharedDataContext) I enumerate through the collection and set the databindings.

This is a bit of a work in progress and I'm not 100% happy with it yet (things like cleaning up the collection are concerning me slightly), but I hope it gives you some ideas.

HTH

Simon

Simon
A: 

I ended up tackling my problem from a different route. I created, for example, a "SortedComboBox" control that derived from the standard ComboBox. It defined its own ItemSource, and when its ItemsSource changed it sorts the items and then sets the ItemsSource on the base class. It works well enough, and only takes a bit of XAML changes to get the desired effect

Joe