4

I have an ItemsControl and I set the ItemsPanel to a Canvas. The Canvas needs to be able to dynamically size with the content I put in it, and I need to be able to scroll when content runs off the bounds of the control. The trouble is I can't get the content to scroll. I have the scroll bar visibilities set to auto, so I don't end up seeing the scroll bars pop up when content runs off the edge.

I tried both putting the ItemsControl inside a ScrollViewer, and I tried using a ScrollViewer in the ItemsControl's Template.

Here's the ItemsControl inside the ScrollViewer:

<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
    <ItemsControl ItemsSource="{Binding Tiles}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding Left}" />
                <Setter Property="Canvas.Top" Value="{Binding Top}" />
            </Style>
        </ItemsControl.ItemContainerStyle>

        <ItemsControl.ItemTemplateSelector>
            ...
        </ItemsControl.ItemTemplateSelector>
    </ItemsControl>
</ScrollViewer>

And here it is with the ScrollViewer in the Template:

<ItemsControl ItemsSource="{Binding Tiles}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Canvas.Left" Value="{Binding Left}" />
            <Setter Property="Canvas.Top" Value="{Binding Top}" />
        </Style>
    </ItemsControl.ItemContainerStyle>

    <ItemsControl.Template>
        <ControlTemplate>
            <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
                <ItemsPresenter />
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>

    <ItemsControl.ItemTemplateSelector>
        ...
    </ItemsControl.ItemTemplateSelector>
</ItemsControl>

This post on MSDN seemed promising, but implementing it on my code, or even explicitly with a Canvas in lieu of a WrapPanel wasn't working (or, should I say, I wasn't able to get it to work).

I've also taken a look at this post but the solution doesn't work for me as I need the canvas to be able to size with the content (otherwise the scroll bars are always visible).

Thank you kindly, in advance!

Ian Wold
  • 132
  • 7
  • 12

1 Answers1

4

The canvas's width/height when not explicitly set, will inherit from the ItemsControl. The "dynamic sizing" behavior you're expecting isn't how panels sizing and layout works out of the box.

You options are to:

  1. Explicitly set the ItemsControl Width/Height.
  2. Explicitly set the Canvas Width/Height.
Michael G
  • 6,695
  • 2
  • 41
  • 59
  • 1
    Ah, that's what I was fearing. Perhaps it would work if I calculated the size of the contents of the canvas as I add them, and update the width/height that way? Edit: Yes indeed, it works as I need. Thanks for helping sort this out, Michael! – Ian Wold Feb 13 '18 at 01:16