How to make WrapPanel to show vertical scrollbar when children are full with or without ScrollViewer
Asked Answered
C

2

7

I have a WrapPanel and buttons are programmatically created and added as children of the WrapPanel. So, I want to show vertical scrollbar when the WrapPanel is full of buttons (children) to be able to add more buttons continuously.

If we need a scrollbar shown, do we have to bring ScrollViewer? Isn't there a way without ScrollViewer? What I want to get is, because the WrapPanel is of small size, I want a scrollbar to be shown only when needed (like full of children).

My code is simple as below (WrapPanel inside Grid and the Grid is inside TabControl)

Many thanks always for your excellence.

Update: I struggled in finding solution on internet for even several days. And I tried put WrapPanel inside ScrollViewer. However, though I set the VerticalScroll to auto, the vertical scrollbar is always shown even when the WrapPanel doesn't have any children.

Furthermore, when I intentionally make the WrapPanel full of children (buttons), the vertical scrollbar of ScrollViewer doesn't provide scrolldown availability. And the buttons at the bottom line of WrapPanel shown cut and more, I can't scroll down to see beyond the button at the bottom line. I made buttons to be placed beyond the bottom line of WrapPanel intentionally.

With or without, I want the vertical scrollbar to be shown when only needed (full of children). It seems very easy to be done. But it's difficult to make it work properly.

Solution: was provided by Mr. Henk Holterman

                    <DropShadowEffect/>
                </Button.Effect>
            </Button>
            <WrapPanel x:Name="WrapPanelGreen" HorizontalAlignment="Left" Height="180" VerticalAlignment="Top" Width="232" UseLayoutRounding="True" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
        </Grid>
    </TabItem>
</TabControl>

And below is my simple code which make button programmatically and add as a child of WrapPanel.

for (int k = 0; k < Overviews.Length; k++)
{
    Button btnoverviewcontent = new Button();

    ToolTip tt = new ToolTip();
    tt.Content = "Press this button if you want to modify or delete.";
    btnoverviewcontent.ToolTip = tt;

    btnoverviewcontent.Cursor = Cursors.Hand;

    SolidColorBrush mySolidColorBrush = new SolidColorBrush();
    mySolidColorBrush.Color = Color.FromArgb(255, 101, 173, 241);
    btnoverviewcontent.Background = mySolidColorBrush;

    btnoverviewcontent.Effect = new DropShadowEffect
    {
        Color = new Color { A = 255, R = 0, G = 0, B = 0 },
        Direction = 315,
        ShadowDepth = 5,
        Opacity = 1
    };

    btnoverviewcontent.Padding = new Thickness(3, 3, 3, 3);
    btnoverviewcontent.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Stretch;
    TextBlock textBlock = new TextBlock()
    {
        Text = Overviews[k],
        TextAlignment = TextAlignment.Left,
        TextWrapping = TextWrapping.Wrap,

    };

    btnoverviewcontent.Content = textBlock;
    btnoverviewcontent.BorderThickness = new Thickness(0, 0, 0, 0);
    btnoverviewcontent.FontStretch = FontStretches.UltraExpanded;
    btnoverviewcontent.Margin = new Thickness(5, 5, 5, 5);

    WrapPanelGreen.Children.Add(btnoverviewcontent);
    btnoverviewcontent.Click += new RoutedEventHandler(OnOverviewClick);
Concentric answered 26/2, 2016 at 6:28 Comment(3)
I would direct you to: https://mcmap.net/q/488089/-wpf-wrap-panel-and-scrolling It's a good breakdown of the basic function of the WrapPanel with some comments on how to implement scrolling with it.Maryleemarylin
@HenkHolterman, please see my updated question. Thank you for your precious comment.Concentric
@TernaryTopiary, Many thanks for your direction. However, I also evaluated the linked page and at this time fully again. My problem is Children(button) are made programmatically and the size of childs are different according to their text content. Therefore, I can't adopt the second solution..Please see my updated question.Concentric
F
14

The idea in WPF is that every component has only its own job and if you want certain behavior, you combine multiple components to create the view you are looking for.

This means that in order to get a scroll bar for a panel, you will have to wrap it in a ScrollViewer component. That’s the purpose of the ScrollViewer and that’s the only (sane) solution to solve this.


However, though I set the verticalscroll to auto, the verticalscrollbar is always shown even when the Wrappanel doesn't have any child […]

Then you seem to be using the ScrollViewer incorrectly, or wrapping the wrong element. It should look like this:

<ScrollViewer VerticalScrollBarVisibility="Auto">
    <WrapPanel>
        <!-- Any number of components here -->
    </WrapPanel>
</ScrollViewer>

If I place lots of example labels inside that, then I do get a scroll bar as soon as the window is not large enough to show them all. But if there is enough room, the scroll bar is not displayed.

Note that the ScrollViewer itself needs to have the proper dimensions in the parent element, so make sure that it’s not larger than the visible area. It is also necessary for the WrapPanel (or whatever other element you wrap with the ScrollViewer) to have auto widths and heights. Otherwise, with fixed dimensions, the dimensions of the panel will not change as you modify the panel’s content and as such the scrolling status will not change.


See this complete example with a dynamic number of elements:

<Window x:Class="WpfExampleApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="300" Width="200">
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <WrapPanel Name="panel">
            <Button Click="Button_Click">Add child</Button>
        </WrapPanel>
    </ScrollViewer>
</Window>

Code-behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Label element = new Label() { Content = "This is some example content" };
        panel.Children.Add(element);
    }
}
Foehn answered 26/2, 2016 at 6:50 Comment(7)
I was going to point out that the WrapPanel does have a ScrollViewer component in it already, but I had a play in Visual Studio and came to the conclusion that even if you force it to show the scroll viewer all the time (via the WrapPanel's XAML tag: ScrollViewer.VerticalScrollBarVisibility="Visible", it doesn't actually offer scrolling for the end user. I agree with this answer.Maryleemarylin
@Maryleemarylin The attached property ScrollViewer.VerticalScrollBarVisibility can be attached to every component but has only an effect for controls that actually have a scroll bar (e.g. ListViews). Panels in general do not include any scroll functionality but only offer the various layouting capabilities so they will always have to be wrapped inside a ScrollViewer.Foehn
@poke, I really appreciate your precious answer. I also tried to wrap like your suggestion but as I updated, the childrens are made programmatically and set as a child of Wrappanel. Is this different from your suggestion? My scrollbar shows even when it's not needed and doesn't work when it's needed..Oh..God..I tried to find solution several days and finally asking to stackoverflow...Concentric
@KayLee It doesn’t matter how the elements are added to the WrapPanel, WPF will automatically redraw the controls and reevaluate the scrollbar status every time the content changes. I’ve added a more complete example to my answer. If you are still having issues, please expand your question with your current code.Foehn
@HenkHolterman, Oh....I followed your suggestion setting the Height and Width of Wrappanel to auto(not specified number). And it's working finely as we desire. However, I regret you didn't suggest as an Answer. Thank you so much to you and Mr. Poke as well.Concentric
(@HenkHolterman Auto is a valid value for widths and heights in XAML which sets the property value to Double.NaN and which is also the default)Foehn
Thank you all 2 gentlemen. I accepted Mr. Poke's answer as per Mr. Henk Holterman's kindness.Concentric
D
2

...just in case someone is looking at this post after 4.5 years and feels, that the solution doesn't help at all: I had a similar problem, which was caused by a StackPanel into which my ScrollViewer and dynamic buttons where put in... Seems like the StackPanel expands the height limitless, so that the ScrollViewer and the WrapPanel always expand their height past the window-bounds. so you couldn't scroll at all. Wrapping that StackPanel into a ScrollViewer helped in my case (although eventually i had to change the controls in the end...)

regards

Dynamotor answered 29/7, 2020 at 13:58 Comment(1)
The year is 2020 and it still feels like the stack panel should handle its own scrolling if it exposes the scrollers' properties.Writhe

© 2022 - 2024 — McMap. All rights reserved.