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:
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)
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.