Question

Background:

I am generating the UI for a settings page. The settings are stored within a Dictionary as the settings will be different for each object in question.

Problem:

The ScrollableHeight of a ScrollViewer is not acurate to the size of the content. When the content of the ScrollViewer changes the ScrollableHeight is not reset, but appends the height of the new content.

When:

I am generating content within a Grid, which is a child element within the ScrollViewer. The content being RowDefinitions where name-value pairs are displayed as TextBlocks and TextBoxes. When a different object is selected in order to edit its properties, the Grid's Children are cleared and the UI to display the properties is regenerated. As I mentioned before in the problem defintion, the generated content's height is appended to the ScrollViewer's ScrollableHeight property.

What I have learned:

My first thought was to clear the ScrollViewer's ScrollableHeight and for each row added append the height of the row in order to achieve the correct size. The issue is that ScrollableHeight cannot be set (private setter).

Code:

XAML:

<ScrollViewer Name="svScroller"  Grid.Row="0">
    <Grid x:Name="gdPropertyGrid" Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="35*" />
            <ColumnDefinition Width="65*" />
        </Grid.ColumnDefinitions>
    </Grid>
</ScrollViewer>

C#:

//Get Selected Item
var listBox = ((ListBox)sender);
var provider = listBox.SelectedItem as IProviderConfiguration;

if (provider != null)
{
    tbTitle.Text = String.Format("Properties for {0}",provider.Name);

    int rowCount = 0;

    PropertyGrid.Children.Clear();

    //Get properties
    foreach (var property in provider.Properties)
    {
        //Create Grid Row
        var rowDef = new RowDefinition() {Height = new GridLength(30)};
        PropertyGrid.RowDefinitions.Add(rowDef);

        //Create Name Label
        var tbPropertyName = new TextBlock { 
                Text = property.Key,
                VerticalAlignment = VerticalAlignment.Center 
        };

        //Create Value input
        var tbPropertyValue = new TextBox {
                Text = property.Value.ToString(), 
                VerticalAlignment = VerticalAlignment.Center
        };

        //Add TextBlock & TextBox Grid
        PropertyGrid.Children.Add(tbPropertyName);
        PropertyGrid.Children.Add(tbPropertyValue);

        //Set Grid.Row Attached property
        Grid.SetRow(tbPropertyName, rowCount);
        Grid.SetRow(tbPropertyValue, rowCount);

        Grid.SetColumn(tbPropertyValue, 1);

        rowCount++;
    }

 }
Was it helpful?

Solution

That is the expected behavior of ScrollViewer.ScrollableHeight, from MSDN:

Gets a value that represents the vertical size of the content element that can be scrolled.

Perhaps you are looking for ScrollViewer.ViewPortHeight? Or maybe you're looking for the ScrollViewer to stretch until a certain point before scrolling. In that case you'll need to look at another solution.

EDIT

The bug is you do not clear the RowDefinitions, hence the ScrollableHeight always appears to be appended to, since you constantly add new rows! My suggestion is you switch to using another ListBox and go with a Master-Detail pattern.

OTHER TIPS

I agree with @sixlettervariables, from your description of the problem it sounds like you are trying to do something with the wrong property. It's not clear to me precisely what your desired outcome is, I assume however that you want to be able to have different numbers of items in the same scroll viewer and have it expand as needed to display as many as possible at runtime.

ScrollViewer.ViewPortHeight lets you set the visible area and is a read/write property, and scrollbars will (by default) appear automatically when the content is too big to fit in the visible area.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top