0
votes

I caught myself stuck in this problem for a while and I seem to be unable to manage it. I created a UserControl named TaskListControl that essentially is a list of another UserControl named TaskListItemControl and I want it to show the vertical ScrollBar when the content overflows but it doesn't happen.

After some searching and test I tried to break down the CustomControl because I suspect that the problem is related to the undefined space occupation by the items list. I included the ScrollViewer inside a Grid and placed it inside the MainWindow, but nothing changes.

Here is the code for the TaskListItem contained inside the list:

<UserControl x:Class="CSB.Tasks.TaskListItemControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:CSB.Tasks"
         xmlns:core="clr-namespace:CSB.Tasks.Core;assembly=CSB.Tasks.Core"
         mc:Ignorable="d"
         Height="70"
         d:DesignHeight="100" d:DesignWidth="400">

<!-- Custom control that represents a Task. -->
<UserControl.Resources>
    <!-- The control style. -->
    <Style x:Key="ContentStyle" TargetType="{x:Type ContentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">

                    <Border x:Name="ContainerBorder" BorderBrush="{StaticResource LightVoidnessBrush}"
                            Background="{StaticResource DeepVoidnessBrush}"
                            BorderThickness="1" 
                            Margin="2">

                        <!-- The grid that contains the control. -->
                        <Grid Name="ContainerGrid" Background="Transparent">

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>

                            <!-- Border representing the priority state of the Task:
                            The color is defined by a ValueConverter according to the PriorityLevel of the Task object. -->
                            <Border Grid.Column="0"
                                    Width="10"
                                    Background="{Binding Priority, Converter={local:PriorityLevelToRGBConverter}}">
                            </Border>

                            <!-- Border containing the Task's informations. -->
                            <Border Grid.Column="1" Padding="5">
                                <StackPanel>
                                    <!-- The title of the Task. -->
                                    <TextBlock Text="{Binding Title}" FontSize="{StaticResource TaskListItemTitleFontSize}" Foreground="{StaticResource DirtyWhiteBrush}"/>

                                    <!-- The customer the Taks refers to. -->
                                    <TextBlock Text="{Binding Customer}" Style="{StaticResource TaskListItemControlCustomerTextBlockStyle}"/>

                                    <!-- The description of the Task. -->
                                    <TextBlock Text="{Binding Description}"
                                               TextTrimming="WordEllipsis"
                                               Foreground="{StaticResource DirtyWhiteBrush}"/>
                                </StackPanel>
                            </Border>

                            <!-- Border that contains the controls for the Task management. -->
                            <Border Grid.Column="2"
                                    Padding="5">

                                <!-- Selection checkbox of the Task. -->
                                <CheckBox Grid.Column="2" VerticalAlignment="Center"/>
                            </Border>

                        </Grid>

                    </Border>

                    <!-- Template triggers. -->
                    <ControlTemplate.Triggers>

                        <DataTrigger Binding="{Binding IsSelected}" Value="True">
                            <Setter Property="Background" TargetName="ContainerBorder" Value="{StaticResource VoidnessBrush}"/>
                            <Setter Property="BorderBrush" TargetName="ContainerBorder" Value="{StaticResource PeterriverBrush}"/>
                        </DataTrigger>

                        <EventTrigger RoutedEvent="MouseEnter">
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0:0" To="{StaticResource LightVoidness}" Storyboard.TargetName="ContainerGrid" Storyboard.TargetProperty="Background.Color"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>

                        <EventTrigger RoutedEvent="MouseLeave">
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0:0" To="Transparent" Storyboard.TargetName="ContainerGrid" Storyboard.TargetProperty="Background.Color"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </ControlTemplate.Triggers>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

<!-- Content of the control: assignment of the DataContext for design-time testing. -->
<ContentControl d:DataContext="{x:Static core:TaskListItemDesignModel.Instance}" 
                Style="{StaticResource ContentStyle}"/>

And here is the TaskListControl code:

<UserControl x:Class="CSB.Tasks.TaskListControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:CSB.Tasks"
         xmlns:core="clr-namespace:CSB.Tasks.Core;assembly=CSB.Tasks.Core"
         mc:Ignorable="d" 
         d:DesignHeight="500" d:DesignWidth="500">

<!-- Custom control that represents a list of TaskListItemControl. -->
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <ScrollViewer Grid.Row="0"
                  VerticalScrollBarVisibility="Auto"
                  HorizontalScrollBarVisibility="Auto"
                  DataContext="{x:Static core:TaskListDesignModel.Instance}"
                  Height="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=Height}">

        <!-- The items shown in the list. -->
        <ItemsControl ItemsSource="{Binding Items}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:TaskListItemControl/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

    </ScrollViewer>

</Grid>

As you can see, I set the DataContext in order to test the controls and I can actually see the ScrollBar inside the design preview:

Actual result.

EDIT: I managed to show the ScrollBarbut it seems to overflow the Window that contains the TaskListControl since I bound it's height to the Window height that, obviously, takes in account the titlebar too. Here is the code of the MainWindow where the control is used:

<Window x:Class="CSB.Tasks.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:CSB.Tasks"
    mc:Ignorable="d"
    Title="{StaticResource MainWindow_TitleText}"
    Style="{StaticResource WindowDefaultStyle}"
    Height="500" 
    Width="500"
    WindowStartupLocation="CenterScreen">

<WindowChrome.WindowChrome>
    <WindowChrome ResizeBorderThickness="{Binding ResizeBorderThickness}"
                  GlassFrameThickness="0"
                  CornerRadius="{Binding CornerRadius}"/>
</WindowChrome.WindowChrome>

<local:TaskListControl>
    <local:TaskListControl/>
</local:TaskListControl>

The TaskListControl is placed directly in the Window since I tried to put it in almost every type of "container" (Border, StackPanel, Grid, etc.) but no luck at all, the height still overflows.

Since I'd like to handle the height directly in the UserControl definition avoiding to do so every time I use it:

  • Where should I place the TaskListControl inside the MainWindow (what type of container)?
  • In which way should I set the height of the TaskListControl inside the UserControl definition (now it's bound to the Window height, but it's not correct at all)?

Here is the result of what I accomplished until now (you can see the bottom scroll button missing):

Final result

Does anyone have any suggestions? Thank you all in advance for the help.

1
So your items are clipped when overflow without showing the scrollbar?Dmitry
Did you try setting the VerticalScrollBarVisibility attached property on the itemscontrol itself? I think that control brings its own ScrollViewer... Also, it would be slightly more performant to avoid a user control inside the DataTemplate, just put the contents of TaskListItemControl inside the data template directly (if possible)Ehssan
@Ehssan I tried setting the attachedproperty directly on the itemscontrol but nothing changed. Thanks for the performances tip, I'll try it.Belfed
Did you try without the Height binding? Then it should use the * heigth of the Grid and only fill the available space.mami
@mami Yes, if I do not set the Height inside the ScrollViewer the ScrollBar is not visible at all, even if the * height of the Grid is used. Since the question could potentially become quite long, you can find the complete project if you want to test it by yourself drive.google.com/open?id=1eOXEeLEvGAkdOW8RvbTV_pMnKFl4zoQc. Thank you for the help.Belfed

1 Answers

1
votes

For debugging such problems, the best way is to set scrollbar visibility to Visible so you can see how your ScrollViewer grows. Probably it grows bigger than the screen size and if you set the scrollbar visibility to Visible, the bottom scroll button will be missing.

Maybe you have put your user control inside a container that has a height of * so it grows bigger than the screen and the scrollbar will never be shown.

Update: I have checked your project, I believe the problem is the Grid in Windows.xaml. In rows 23-27 change the order of the last two RowDefinitions like this:

<Grid.RowDefinitions>
    <RowDefinition Height="{Binding TitleHeight}"/>
    <RowDefinition Height="*"/>
    <RowDefinition Height="Auto"/>
</Grid.RowDefinitions>