views:

28

answers:

2
    <ItemsPanelTemplate x:Key="lbWrapPanelItemsPanelTemplate">
        <wp:WrapPanel Margin="2" Background="Beige" HorizontalAlignment="Stretch">
        </wp:WrapPanel>
    </ItemsPanelTemplate>

.....

<Grid Background="LightCoral" MinWidth="500" MinHeight="500">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <sdk:GridSplitter Grid.Column="0" Background="AliceBlue" />

    <StackPanel Grid.Column="0" FlowDirection="LeftToRight">
        <Button Width="40">Left</Button>
        <Button Width="40">Right</Button>
    </StackPanel>

    <Grid Background="Bisque" Grid.Column="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="100"></RowDefinition>
        </Grid.RowDefinitions>

        <ListBox ItemsPanel="{StaticResource lbWrapPanelItemsPanelTemplate}" x:Name="bookListBox" HorizontalAlignment="Stretch"  Grid.Row="0" ItemsSource="{Binding Path=BookSource}" ItemTemplate="{StaticResource dirtSimple}"  />

        <wp:WrapPanel Grid.Row="1">
            <Button Width="200" Command="{Binding Path=AddItemCommand}">Bottom</Button>
            <Button Width="200" Command="{Binding ChangeTemplateCommand}" CommandParameter="{StaticResource vmDataTemplate}">White</Button>
            <Button Width="200" Command="{Binding ChangeTemplateCommand}" CommandParameter="{StaticResource vmDataTemplate2}">Lavender</Button>
        </wp:WrapPanel>
    </Grid>

</Grid>

The ListBox works perfectly, except that the (Beige) WrapPanel seems to extend off into infinity. As more items are added to the ListBox, it just scrolls to the right instead of wrapping. If I add a concrete size to the WrapPanel, that causes things to wrap, but (obviously) causes the items in the LB to be shown in a subset of all available space.

Is there a way to tell the WrapPanel to take up all available space and no more?

+1  A: 

I always have trouble getting the WrapPanel to work correctly inside ListBoxes (likely something in the template related to the ScrollViewer in it). If you take your code and put it inside an ItemsControl instead of a ListBox you'll see it work perfectly as-is.

You can affect the ScrollViewer inside your WrapPanel and force it to wrap:

<ListBox HorizontalAlignment="Stretch" ItemsSource="{Binding foo}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <tk:WrapPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

Note the ScrollViewer.HorizontalScrollBarVisibility set on the ListBox - this prevent a horizontal scrollbar, which forces your WrapPanel to wrap.

Adam Sills
I just added Stretch, but no effect. Full XAML is there. Thanks much for your help.
Adam
Ha - even if I add Width="300" to the ListBox, it just creates a tiny 300px wide LB that *still* scrolls the same way :(
Adam
I hate the TK's WrapPanel. It's the only control that never behaves right for me. I've got a way to work around this, but it's ugly. Give me a minute more :)
Adam Sills
Sure. Are there better WrapPanels out there in your opinion? How Silverlight 4 doesn't have a WrapPanel built in is beyond me
Adam
The WrapPanel in the TK is fine, it just doesn't work intuitively in some controls (ListBox for instance), even though ListBox's super class works like you'd expect.
Adam Sills
You've already gone above and beyond, but do you happen to know how to write the binding so that it works even if the template is written up in the Resources section, instead of embedded in the LB like you have it? The binding doesn't seem to like the name reference when in Resources. Would some sort of ancestor binding work?
Adam
Not in Silverlight, no. You'd have to include the ItemsPanelTemplate directly within the ListBox because there are no ancestor bindings in Silverlight (just Self and TemplatedParent).
Adam Sills
Well, you could also do some funkiness like an attached property to set it (use the VisualTree helper in the property change callback to find the parent and set the value that way). But ultimately it's probably easier just to include the ItemsPanelTemplate directly apply a Style to it that is in your Resources.
Adam Sills
mkay - thanks again for your help.
Adam
BTW the reason I wanted to have this as a resource and not embedded was because I wanted to be able to swap it in and out - sort of let the user click a button and change the appearance of the LB. I assume that's not really possible once you embed the template into the control.
Adam
FYI - look at the answer again. I updated it with a solution to force the WrapPanel to wrap by disabling the horizontal scroll bar.
Adam Sills
Hopefully that'll work better than any other hack-ish solutions :)
Adam Sills
Well, I'll be damned. That worked. You are a god among men, Mr. Adam Sills. Thank you so unbelievably much.
Adam
A: 

You can fix this by binding the WrapPanel's width to the ActualWidth of the ListBox:

<WrapPanel Width="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=ActualWidth"}

(unless, of course, that's something that only works in WPF and not Silverlight, which I dunno.)

The curious thing, though, is why the ListBox does this and the ItemsControl doesn't. The WrapPanel has the correct margin, and the items it contains wrap correctly, in this page:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="700"/>
    </Grid.ColumnDefinitions>
    <ItemsControl 
      Background="Azure"
      Margin="5">
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <WrapPanel 
            Background="Lavender"
            Margin="10"/>
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <ListBoxItem>adsk flaskjf lkasjd flaskdjf laskdj</ListBoxItem>
      <ListBoxItem>adsk flaskjf lkasjd flaskdjf laskdj</ListBoxItem>
      <ListBoxItem>adsk flaskjf lkasjd flaskdjf laskdj flaksjf laskjf aslkjf alsjkf lsafdkj </ListBoxItem>
      <ListBoxItem>adsk flaskjf lkasjd flaskdjf laskdj flaksjf laskjf aslkjf alsjkf lsafdkj </ListBoxItem>
      <ListBoxItem>adsk flaskjf lkasjd flaskdjf laskdj flaksjf laskjf aslkjf alsjkf lsafdkj </ListBoxItem>
      <ListBoxItem>adsk flaskjf lkasjd flaskdjf laskdj flaksjf laskjf aslkjf alsjkf lsafdkj </ListBoxItem>      
    </ItemsControl>
  </Grid>
</Page>

Change the ItemsControl to a ListBox and it doesn't.

Robert Rossney
No ancestor binding in Silverlight. "X" works in WPF but not in Silverlight seems to be a common theme...
Adam