views:

673

answers:

3

Is it possible to do something like this:

    <ListBox>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Text}" Grid.Column="{Binding Column}" Grid.Row="{Binding Row}"  />
            </DataTemplate>                
        </ListBox.ItemTemplate>
    </ListBox>

The items source would be something like a List of objects that had the Text, Column and Row properties.

Is this possible? I really want to have my data grid be data bound.

+1  A: 

What you have won't work because Silverlight wraps each item -- each instance of the DataTemplate -- in a ListBoxItem, and the Grid.Column and Grid.Row attached properties need to be applied to that ListBoxItem, not to the TextBox that becomes the content of that ListBoxItem.

The good news is that you can set attributes on the implicit ListBoxItem using ListBox.ItemContainerStyle.

The bad news is that ItemContainerStyle doesn't readily support binding. So you can't use it to set the Grid.Column and Grid.Row attached properties to attributes of the data item at hand.

One solution that I've used is to subclass ListBox and set up the binding in PrepareContainerForItemOverride. Here's a very crude, hardwired example:

public class GriderrificBox : ListBox
{
  protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
  {
    base.PrepareContainerForItemOverride(element, item);

    FrameworkElement fe = element as FrameworkElement;
    if (fe != null)
    {
      BindingOperations.SetBinding(fe, Grid.RowProperty,
        new Binding { Source = item, Path = new PropertyPath("Row") });
      BindingOperations.SetBinding(fe, Grid.ColumnProperty,
        new Binding { Source = item, Path = new PropertyPath("Column") });
    }
  }
}

Usage:

<local:GriderrificBox>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBox Text="{Binding Text}" />
    </DataTemplate>
  </ListBox.ItemTemplate>
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>
      <Grid />
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
</local:GriderrificBox>

There are (at least) two major uglinesses with this code: first, you still need to explicitly specify ItemsPanel in XAML, even though the control works only with Grid panels; and second, the binding paths are hardwired into the code. The first can be addressed by using the normal control default style mechanism, and the second by defining properties such as RowBindingPath and ColumnBindingPath which PrepareItemForContainerOverride can consult instead of using hardwired paths. Hopefully enough to get you going anyway!

itowlson
There is still the problem that a `Grid` requires the set of Rows and Columns to be defined in its `RowDefinitions` and `ColumnDefinitions` collection.
AnthonyWJones
I don't know if this works. Part of the problem is that there is no BindingOperations (at least that I can find) in SL3. I tried to just do a SetBinding on the element object, but that didn't work either. itowlson: have you gotten this to work with SL3?
skb
BindingOperations is a static class in the System.Windows.Data namespace. Yes, I have had this working with SL3 (albeit using a Canvas rather than a Grid, but the concept is the same, with due acknowledgement to the issue raised by AnthonyWJones).
itowlson
+2  A: 

The Grid just isn't suitable for the usage you are trying to put it to here. Its expecting the set of available rows and columns to be defined upfront before you start assigning elements to the cells.

If you are trying to create a list box that makes use of both horizontal and vertical space then perhaps a WrapPanel from the Silverlight Toolkit would be better basis.

On the other hand if you are trying to create a "Data grid" then consider transposing or grouping the columns in each row in the model, then you can use the DataGrid instead of a ListBox

AnthonyWJones
A: 

If you are interested in support of such scenario in future version of Silverlight please vote for porting of Adobe Flex Grid layout, which will work perfectly in such scenario

Alexey Zakharov