7
votes

Ok here's my code. Note that the StackPanel is directly in a UserControl.

<UserControl>
    <StackPanel Orientation="Horizontal">

        <ScrollViewer Width="450"
                      VerticalScrollBarVisibility="Auto"
                      HorizontalScrollBarVisibility="Disabled">

            <Rectangle Width="400" Height="4000" Fill="BlanchedAlmond"/>
        </ScrollViewer>

        <ScrollViewer VerticalScrollBarVisibility="Auto"
                      HorizontalScrollBarVisibility="Disabled">

            <ItemsControl BorderBrush="Green"
                          BorderThickness="2"
                          ItemsSource="{Binding Path=MyObservableCollection}"
                          ItemTemplate="{StaticResource FatTemplate}">

                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>

            </ItemsControl>
        </ScrollViewer>

    </StackPanel>
</UserControl>

(Code EDITED)

Note that the rectangle is just there because the content of that scroll viewer is irrelevant.

The problem is that the WrapPanel just expands horizontally and doesn't wrap...

I found a few solutions:

  1. Giving absolute width to the WrapPanel (but then it doesn't resize with the window).

  2. Binding width to its parent width - either ItemsControl or ScrollViewer (ScrollViewer worked better in a limited situation like this one).

    Width="{Binding RelativeSource=
        {RelativeSource FindAncestor,
        AncestorType={x:Type ScrollViewer}},
        Path=ActualWidth}"
    

The problem with this technique is that if a control is beside it in a StackPanel or Grid, you need to bind it to it's parent size minus the control next to it. Then comes the hard stuff. I built a converter which applies mathematical operations on the number received so I could subtract a given width from its parent width:

Width="{Binding RelativeSource=
    {RelativeSource FindAncestor,
    AncestorType={x:Type UserControl}},
    Path=ActualWidth,
    Converter={StaticResource Convertisseur_Size_WXYZ}, 
    ConverterParameter=-260}"

But still, since you can't bind a value you pass to a ConverterParameter,

ConverterParameter={Binding ...} (doesn't work)

I want:

  • to be able to resize my app with my WrapPanel and ScrollViewer resizing well,
  • my UserControl to be easily maintainable,
  • my code cleaner than these big binding expressions which rely on parent control's Type.

What's a better solution?

Note: If anything isn't clear, I can add detail.

1
It works fine in a grid instead of a StackPanel, maby its a bit of a resizing bug with the StackPanel or something?Gab
I don't think it is a bug. If you put a control inside a grid cell it will by default be sized to perfectly fit the available space in that cell. The StackPanel will not do that. Is there are reason why you can't use a Grid with two cells instead of a StackPanel?haagel
Ya i might just use a grid. StackPanel seemed nicer at first beacause its a little bit cleaner for the eye when you look at the code but as Kent said, it causes problems.Gab

1 Answers

9
votes

Why would it wrap when the ScrollViewer allows horizontal scrolling? You should disable horizontal scrolling in the ScrollViewer:

<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">

EDIT AFTER YOUR EDIT: It's because your StackPanel is oriented horizontally. A horizontally-oriented StackPanel will give whatever width its child requests to it - it won't constrain it at all. Use the right panel, and you'll be fine. Likely you just want a Grid with two columns.