Answered by:
Extend last column of listview

Question
-
Hello,
I need to extend the last column of my listview. I want to make it so that all my ListView cells fill up all available horizontal space, and not leave any awkward whitespace on the right. Additionally I also want to ensure that the columns size themselves to fit their contents.
Please advice
Thank You
- MThursday, May 21, 2009 6:17 PM
Answers
-
You could use a Converter to calculate the suitable width of GridViewColumn in the Binding of Width.
Below is a simple demo project that shows how to calculate the 'fill' width of GridViewColumn.
Run the program, you will find the last column of ListView can be extended and fill all the available horizontal space.
Hope it helps.
XAML
<Window x:Class="ListViewSortDescriptions.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ListViewSortDescriptions" Title="Window1" Height="300" Width="800"> <Window.Resources> <ObjectDataProvider x:Key="EmployeeInfoDataSource" ObjectType="{x:Type local:myEmployees}"/> <DataTemplate x:Key="MyDataTemplate"> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" Margin="-6,-2,-6,-2"> <StackPanel Margin="6,2,6,2"> <TextBlock Text="{Binding MySpecialBinding}"/> </StackPanel> </Border> </DataTemplate> <Style x:Key="MyItemContainerStyle" TargetType="{x:Type ListViewItem}"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Stretch" /> </Style> <local:WidthConverter x:Key="WidthConverter"></local:WidthConverter> </Window.Resources> <Grid> <ListView x:Name="MyListView" ItemsSource="{Binding Source={StaticResource EmployeeInfoDataSource}}" > <ListView.View> <GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Employee Information"> <GridViewColumn x:Name="gridClm_SelectRow" Width="35"> <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000000" BorderThickness="1,1,0,0" Margin="-6,-2,-6,-2"> <CheckBox Margin="0" x:Name="cbSelectRow" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" /> </Border> </DataTemplate> </GridViewColumn.CellTemplate> <CheckBox IsEnabled="False" Margin="0" x:Name="chkSelectAll" /> </GridViewColumn> <GridViewColumn Header="First Name" Width="100"> <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" > <StackPanel Width="100" > <TextBlock Text="{Binding FirstName}"/> </StackPanel> </Border> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Last Name" Width="100"> <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" > <StackPanel Width="100" > <TextBlock Text="{Binding LastName}"/> </StackPanel> </Border> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Employee No." Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListView}}, Converter={StaticResource WidthConverter}}" > <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" > <StackPanel > <TextBlock Text="{Binding EmployeeNumber}"/> </StackPanel> </Border> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView> </Grid> </Window>
C#
using System.Windows; using System.Windows.Data; using System.ComponentModel; using System.Collections.ObjectModel; using System.Windows.Controls; using System; using System.Globalization; namespace ListViewSortDescriptions { public partial class Window1 : Window { public Window1() { InitializeComponent(); if (MyListView.ItemsSource != null) { MyListView.Language = System.Windows.Markup.XmlLanguage.GetLanguage("da-DK"); MyListView.Items.Culture = new System.Globalization.CultureInfo("da-DK", false); (CollectionViewSource.GetDefaultView(MyListView.ItemsSource) as ICollectionView).SortDescriptions.Clear(); SortDescription sorter = new SortDescription("FirstName", ListSortDirection.Ascending); (CollectionViewSource.GetDefaultView(MyListView.ItemsSource) as ICollectionView).SortDescriptions.Add(sorter); } } } public class EmployeeInfo { private string _firstName; private string _lastName; private string _employeeNumber; public string FirstName { get { return _firstName; } set { _firstName = value; } } public string LastName { get { return _lastName; } set { _lastName = value; } } public string EmployeeNumber { get { return _employeeNumber; } set { _employeeNumber = value; } } public EmployeeInfo(string firstname, string lastname, string empnumber) { _firstName = firstname; _lastName = lastname; _employeeNumber = empnumber; } } public class myEmployees : ObservableCollection<EmployeeInfo> { public myEmployees() { Add(new EmployeeInfo("Jesper", "Aaberg", "12345")); Add(new EmployeeInfo("Dominik", "Paiha", "98765")); Add(new EmployeeInfo("Yale", "Li", "23875")); Add(new EmployeeInfo("Muru", "Subramani", "49392")); } } /// <summary> /// Calculates the column width required to fill the view in a GridView /// For usage examples, see http://leghumped.com/blog/2009/03/11/wpf-gridview-column-width-calculator/ /// </summary> public class WidthConverter : IValueConverter { /// <summary> /// Converts the specified value. /// </summary> /// <param name="value">The parent Listview.</param> /// <param name="type">The type.</param> /// <param name="parameter"> /// If no parameter is given, the remaning with will be returned. /// If the parameter is an integer acts as MinimumWidth, the remaining with will be returned only if it's greater than the parameter /// If the parameter is anything else, it's taken to be a percentage. Eg: 0.3* = 30%, 0.15* = 15% /// </param> /// <param name="culture">The culture.</param> /// <returns>The width, as calculated by the parameter given</returns> public object Convert(object value, Type type, object parameter, CultureInfo culture) { if (value == null) return null; ListView listView = value as ListView; GridView grdView = listView.View as GridView; int minWidth = 0; bool widthIsPercentage = parameter != null && !int.TryParse(parameter.ToString(), out minWidth); if (widthIsPercentage) { string widthParam = parameter.ToString(); double percentage = double.Parse(widthParam.Substring(0, widthParam.Length - 1)); return listView.ActualWidth * percentage; } else { double total = 0; for (int i = 0; i < grdView.Columns.Count - 1; i++) { total += grdView.Columns[i].ActualWidth; } double remainingWidth = listView.ActualWidth - total; if (remainingWidth > minWidth) { // fill the remaining width in the ListView return remainingWidth; } else { // fill remaining space with MinWidth return minWidth; } } } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { throw new NotSupportedException(); } } }
Wednesday, May 27, 2009 3:19 AM
All replies
-
You could use a Converter to calculate the suitable width of GridViewColumn in the Binding of Width.
Below is a simple demo project that shows how to calculate the 'fill' width of GridViewColumn.
Run the program, you will find the last column of ListView can be extended and fill all the available horizontal space.
Hope it helps.
XAML
<Window x:Class="ListViewSortDescriptions.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ListViewSortDescriptions" Title="Window1" Height="300" Width="800"> <Window.Resources> <ObjectDataProvider x:Key="EmployeeInfoDataSource" ObjectType="{x:Type local:myEmployees}"/> <DataTemplate x:Key="MyDataTemplate"> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" Margin="-6,-2,-6,-2"> <StackPanel Margin="6,2,6,2"> <TextBlock Text="{Binding MySpecialBinding}"/> </StackPanel> </Border> </DataTemplate> <Style x:Key="MyItemContainerStyle" TargetType="{x:Type ListViewItem}"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <Setter Property="VerticalContentAlignment" Value="Stretch" /> </Style> <local:WidthConverter x:Key="WidthConverter"></local:WidthConverter> </Window.Resources> <Grid> <ListView x:Name="MyListView" ItemsSource="{Binding Source={StaticResource EmployeeInfoDataSource}}" > <ListView.View> <GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Employee Information"> <GridViewColumn x:Name="gridClm_SelectRow" Width="35"> <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000000" BorderThickness="1,1,0,0" Margin="-6,-2,-6,-2"> <CheckBox Margin="0" x:Name="cbSelectRow" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" /> </Border> </DataTemplate> </GridViewColumn.CellTemplate> <CheckBox IsEnabled="False" Margin="0" x:Name="chkSelectAll" /> </GridViewColumn> <GridViewColumn Header="First Name" Width="100"> <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" > <StackPanel Width="100" > <TextBlock Text="{Binding FirstName}"/> </StackPanel> </Border> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Last Name" Width="100"> <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" > <StackPanel Width="100" > <TextBlock Text="{Binding LastName}"/> </StackPanel> </Border> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Employee No." Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListView}}, Converter={StaticResource WidthConverter}}" > <GridViewColumn.CellTemplate> <DataTemplate> <Border BorderBrush="#FF000FF0" BorderThickness="2,2,0,0" > <StackPanel > <TextBlock Text="{Binding EmployeeNumber}"/> </StackPanel> </Border> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView> </Grid> </Window>
C#
using System.Windows; using System.Windows.Data; using System.ComponentModel; using System.Collections.ObjectModel; using System.Windows.Controls; using System; using System.Globalization; namespace ListViewSortDescriptions { public partial class Window1 : Window { public Window1() { InitializeComponent(); if (MyListView.ItemsSource != null) { MyListView.Language = System.Windows.Markup.XmlLanguage.GetLanguage("da-DK"); MyListView.Items.Culture = new System.Globalization.CultureInfo("da-DK", false); (CollectionViewSource.GetDefaultView(MyListView.ItemsSource) as ICollectionView).SortDescriptions.Clear(); SortDescription sorter = new SortDescription("FirstName", ListSortDirection.Ascending); (CollectionViewSource.GetDefaultView(MyListView.ItemsSource) as ICollectionView).SortDescriptions.Add(sorter); } } } public class EmployeeInfo { private string _firstName; private string _lastName; private string _employeeNumber; public string FirstName { get { return _firstName; } set { _firstName = value; } } public string LastName { get { return _lastName; } set { _lastName = value; } } public string EmployeeNumber { get { return _employeeNumber; } set { _employeeNumber = value; } } public EmployeeInfo(string firstname, string lastname, string empnumber) { _firstName = firstname; _lastName = lastname; _employeeNumber = empnumber; } } public class myEmployees : ObservableCollection<EmployeeInfo> { public myEmployees() { Add(new EmployeeInfo("Jesper", "Aaberg", "12345")); Add(new EmployeeInfo("Dominik", "Paiha", "98765")); Add(new EmployeeInfo("Yale", "Li", "23875")); Add(new EmployeeInfo("Muru", "Subramani", "49392")); } } /// <summary> /// Calculates the column width required to fill the view in a GridView /// For usage examples, see http://leghumped.com/blog/2009/03/11/wpf-gridview-column-width-calculator/ /// </summary> public class WidthConverter : IValueConverter { /// <summary> /// Converts the specified value. /// </summary> /// <param name="value">The parent Listview.</param> /// <param name="type">The type.</param> /// <param name="parameter"> /// If no parameter is given, the remaning with will be returned. /// If the parameter is an integer acts as MinimumWidth, the remaining with will be returned only if it's greater than the parameter /// If the parameter is anything else, it's taken to be a percentage. Eg: 0.3* = 30%, 0.15* = 15% /// </param> /// <param name="culture">The culture.</param> /// <returns>The width, as calculated by the parameter given</returns> public object Convert(object value, Type type, object parameter, CultureInfo culture) { if (value == null) return null; ListView listView = value as ListView; GridView grdView = listView.View as GridView; int minWidth = 0; bool widthIsPercentage = parameter != null && !int.TryParse(parameter.ToString(), out minWidth); if (widthIsPercentage) { string widthParam = parameter.ToString(); double percentage = double.Parse(widthParam.Substring(0, widthParam.Length - 1)); return listView.ActualWidth * percentage; } else { double total = 0; for (int i = 0; i < grdView.Columns.Count - 1; i++) { total += grdView.Columns[i].ActualWidth; } double remainingWidth = listView.ActualWidth - total; if (remainingWidth > minWidth) { // fill the remaining width in the ListView return remainingWidth; } else { // fill remaining space with MinWidth return minWidth; } } } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { throw new NotSupportedException(); } } }
Wednesday, May 27, 2009 3:19 AM -
Hi Tao,
I just wanted to stretch the last column of the listview to the rest width of the listview. I went through this post of yours, but I am facing the problem in getting the ActualWidth of the listview in Converter. I am getting it as 0.0
I tried to use the Width property , the problem remains as width is coming as NAN.
will you please tell me how to get the width of the list view.
One more thing I want mention here that if I specify the width of the list view in Xaml I am able to get that but If I specify the width of the listView as auto I am not able to get that.
please advice
Thank you
Tuesday, May 17, 2011 2:35 PM