views:

1546

answers:

3

I have a grid with just 1 row. I would like the amount of columns to be determined by the data context of the grid.

For instance, if I have a list of names exposed in an ObservableCollection property called 'Names' that return "Fred", "Joe", and "Anne", I would like three columns in the grid, each with a textbox bound to each name.

My thoughts so far:

1) Build the grid by hand in the code-behind and rebuild it when the ObservableCollection changes. I didn't go with this as it seemed a bit cludgy and not the WPF way of doing things.

2) Create a binding with the Grid's ColumnDefinitions property. This seemed more correct, but there's not a dependency property on the Grid for ColumnDefinition.

A: 

If you can accept having the names in each row rather than each column, you should use the ListView with a GridView View property, and a custom CellTemplate that is just a bound textbox. Something like this:

<ListView ItemsSource="{Binding Names}">
  <ListView.View>
    <GridView>
      <GridViewColumn>
        <GridViewColumn.CellTemplate>
          <!-- Your textbox goes in a DataTemplate here -->    
        </GridViewColumn.CellTemplate>
      </GridViewColumn>
    </GridView>
  </ListView.View>
</ListView>

Solution #2 is unfortunately not possible in XAML. Solution #1 is your best bet if you must have each name in its own column.

Charlie
A: 

If it's a DataGrid, the AutoGenerateColumns property would do this. By using the DataGridTemplateColumn, you can put text box controls instead of just text in there. You'll need to provide an event attached to the AutoGeneratingColumn and in the AutoGeneratingColumnEventArgs (hi, Microsoft, this is carpel tunnel calling), set the Column property to a template column with the text box.

I'd say your ObservableCollection way is simpler ;-P.

Robert Fraser
+1  A: 

I don't think modifying a Grid on the fly is your best bet. Here's another solution. You can use ListBox, but replace the ItemsPanel with another panel of your choosing. ListBox's default ItemsPanel is VirtualizingStackPanel with Orientation set to Vertical. Since you want your items to display horizontally, you can replace it with VirtualizingStackPanel with Orientation set to Horizontal. Of course, you can modify the ItemsTemplate or anything else as you see fit.

<ListBox ItemsSource="{Binding MyCollection}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

I've also used this method before to create a ListBox which displays the items horizontally, but wraps to the next line when it runs out of room on the line, by using a WrapPanel. You can also create your own custom panels and substitute them. I once made a panel that laid out it's items randomly, and used that for a ListBox. Each item in my bound collection was displayed in a random position within the ListBox. Each time the layout refreshed, the items got a new position.

Benny Jobigan