Search code examples
wpflistviewwindows-runtimewinrt-xamllistviewitem

Winrt - ListView Items doesn't fill all space vertically


I have the following listView:

 <ListView x:Name="sportList" Grid.Row="0" Grid.Column="0" SelectionChanged="sportList_SelectionChanged">
     <ListView.ItemContainerStyle>
         <Style TargetType="ListViewItem">
             <Setter Property="HorizontalContentAlignment" Value="Stretch" />                        
         </Style>
     </ListView.ItemContainerStyle>
     <ListView.ItemTemplate>
         <DataTemplate>
             <TextBlock Text="{Binding}" Margin="15,0,0,0" />
         </DataTemplate>
     </ListView.ItemTemplate>
 </ListView>

It produces the following Listview control:

enter image description here

I would like to stretch the listviewitems vertically, in order to fill all the empty space. Something similar to this (achieved specifing a fixed height for the textblock)

enter image description here


Solution

  • You have to bind the Height (or MinHeight) of ListViewItem to the ActualHeight of the ListView. Of course we need a Converter to convert the ActualHeight to the equal Height for each item:

    <ListView x:Name="sportList" Grid.Row="0" Grid.Column="0"
              ScrollViewer.VerticalScrollBarVisibility="Disabled" 
              ScrollViewer.CanContentScroll="False" UseLayoutRounding="True">
        <ListView.Resource> 
           <local:AutoFillHeightConverter x:Key="hc"/>
        </ListView.Resource>
        <ListView.ItemContainerStyle>
          <Style TargetType="ListViewItem">
             <Setter Property="HorizontalContentAlignment" Value="Stretch" />
             <Setter Property="MinHeight" Value="{Binding ActualHeight, 
                     RelativeSource={RelativeSource AncestorType=ListView}, 
                  Converter={StaticResource hc}, ConverterParameter=win@sportList}"/>
          </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
          <DataTemplate>
             <TextBlock Text="{Binding}" Margin="15,0,0,0" />
          </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    Note that your requirement means we don't need the vertical ScrollBar. So we'd better disable or hide it. Also set CanContentScroll to false and UseLayoutRounding to true for better (more exactly set height) rendering.

    Here is the AutoFillHeightConverter class (that we embed an instance in the ListView's Resource):

    public class AutoFillHeightConverter : IValueConverter {
        object IValueConverter.Convert(object value, Type targetType, object parameter,
                                       System.Globalization.CultureInfo culture)
        {
            var p = parameter as string;
            var win = Application.Current.Windows.Cast<Window>()
                                 .First(w => w.Name == p.Split('@')[0]);
            var lv = win.FindName(p.Split('@')[1]) as ListView;
            var lvh = Convert.ToDouble(value);            
            return lv.Items.Count == 0 ? Binding.DoNothing : (lvh / lv.Items.Count);
        }
    
        object IValueConverter.ConvertBack(object value, Type targetType, 
                           object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }    
    

    Note about the ConverterParameter of the Binding, we set it to a string. This string includes 2 parts separated by a @. The first part should be the Window's Name, the second part should be the ListView's Name. We need these Names to access the ListView instance inside the Convert method to convert the height.