none
"Star" size of a ListView column

    Question

  • Hi,

    is there a way to set one column of a ListView to fill the remaining available width of the view window ? Something like star size in Grid.

     

    Thanks

    Jan

    Thursday, April 12, 2007 4:14 PM

Answers

  • AFAIK, there's no straight-forward way to achieve this. GridViewColumns can either be fixed with or "auto" width by either not setting Width or by setting explicitly to Double.NaN. "Auto" width though just means that the columns sizes to the max width of any rows contents for that column.

     

    That said, I guess it would be possible to bind the Width of a GridViewColumn to the ActualWidth of the ListView with a custom IValueConverter that enumerates all the other columns in the GridView to find out their ActualWidth and subtracts that from the ListView's ActualWidth leaving you with the remainder.

     

    HTH,
    Drew

    Thursday, April 12, 2007 6:11 PM
  • something like this should work

    Assuming there is all the columns have widths except one

     

    Code Snippet

    public class StarWidthConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                ListView listview = value as ListView;
                double width = listview.Width;
                GridView gv = listview.View as GridView;
                for (int i = 0; i < gv.Columns.Count; i++)
                {
                    if (!Double.IsNaN(gv.Columns[i].Width))
                        width -= gv.Columns[i].Width;
                }
                return width -5;// this is to take care of margin/padding
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return null;
            }
        }

    <Window x:Class="WindowsApplication4.Window4"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WindowsApplication4" Height="600" Width="600"
         xmlns:local="clr-namespace:WindowsApplication4"
        >
      <Window.Resources>
        <local:StarWidthConverter x:Key="starWidthConverter"></local:StarWidthConverter>
      </Window.Resources>
      <ListView   Width="400" Background="Beige"  >

        <ListView.View>

          <GridView>

            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="100"/>
            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="50"/>
            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="50"/>
            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}"
                            Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}, Converter={StaticResource starWidthConverter}}"/>
          </GridView>

        </ListView.View>
        <ListViewItem>item1</ListViewItem>
        <ListViewItem>item2</ListViewItem>
        <ListViewItem>item3</ListViewItem>
        <ListViewItem>item4</ListViewItem>
      </ListView>
     
    </Window>


     

     

     

    Friday, April 13, 2007 1:47 PM

All replies

  • AFAIK, there's no straight-forward way to achieve this. GridViewColumns can either be fixed with or "auto" width by either not setting Width or by setting explicitly to Double.NaN. "Auto" width though just means that the columns sizes to the max width of any rows contents for that column.

     

    That said, I guess it would be possible to bind the Width of a GridViewColumn to the ActualWidth of the ListView with a custom IValueConverter that enumerates all the other columns in the GridView to find out their ActualWidth and subtracts that from the ListView's ActualWidth leaving you with the remainder.

     

    HTH,
    Drew

    Thursday, April 12, 2007 6:11 PM
  • This is an interesting idea.

     

    I tried to implement it for a while but I was unsuccessful providing all necessary references to the converter (owner grid, affected column itself). A sample code would be appreciated.

     

    Thanks

    Jan

    Friday, April 13, 2007 1:17 PM
  • something like this should work

    Assuming there is all the columns have widths except one

     

    Code Snippet

    public class StarWidthConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                ListView listview = value as ListView;
                double width = listview.Width;
                GridView gv = listview.View as GridView;
                for (int i = 0; i < gv.Columns.Count; i++)
                {
                    if (!Double.IsNaN(gv.Columns[i].Width))
                        width -= gv.Columns[i].Width;
                }
                return width -5;// this is to take care of margin/padding
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return null;
            }
        }

    <Window x:Class="WindowsApplication4.Window4"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WindowsApplication4" Height="600" Width="600"
         xmlns:local="clr-namespace:WindowsApplication4"
        >
      <Window.Resources>
        <local:StarWidthConverter x:Key="starWidthConverter"></local:StarWidthConverter>
      </Window.Resources>
      <ListView   Width="400" Background="Beige"  >

        <ListView.View>

          <GridView>

            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="100"/>
            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="50"/>
            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="50"/>
            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}"
                            Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}, Converter={StaticResource starWidthConverter}}"/>
          </GridView>

        </ListView.View>
        <ListViewItem>item1</ListViewItem>
        <ListViewItem>item2</ListViewItem>
        <ListViewItem>item3</ListViewItem>
        <ListViewItem>item4</ListViewItem>
      </ListView>
     
    </Window>


     

     

     

    Friday, April 13, 2007 1:47 PM
  • Great.

     

    But since you bind to ListView and not its ActualWidth itself, the converter will be called only once at startup, not when the ListView is resized later. Better would be to bind to ListView's ActualWidth. But then the converter has no reference to the affected ListView. I was unsuccessful passing it through ConvertorParameter.

     

    Thanks anyway,

    Jan

    Friday, April 13, 2007 1:58 PM
  • Why not doing something simple like that:

     

    #region Events Handlers

    /// <summary>

    /// Occurs when list size changed

    /// </summary>

    /// <param name="sender">The event's sender</param>

    /// <param name="e">The event's arguments</param>

    private void lvWorkList_SizeChanged(object sender, SizeChangedEventArgs e)

    {

         if (e.WidthChanged)

         {

              GridView view = lvWorkList.View as GridView;

              double width = lvWorkList.ActualWidth / view.Columns.Count;

              foreach (GridViewColumn col in view.Columns)

              {

                   col.Width = width;

              }

         }

    }

    #endregion

     

    Itzik

    Sunday, April 29, 2007 7:23 AM
  • Here's a solution I came up with, using an attached property:

    Attached property (defined in a DependencyObject-derived class):
     
    Code Block

            public static bool GetAutoSize(DependencyObject obj)
            {
                return (bool) obj.GetValue(AutoSizeProperty);
            }

            public static void SetAutoSize(DependencyObject obj, bool value)
            {
                obj.SetValue(AutoSizeProperty, value);
            }

            // Using a DependencyProperty as the backing store for AutoSize.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty AutoSizeProperty =
                DependencyProperty.RegisterAttached("AutoSize", typeof(bool), typeof(ListTable), new UIPropertyMetadata(false));




    ListView's grid definition:
     
    Code Block

    <GridView AllowsColumnReorder="False">
        <GridViewColumn Header="ID" Width="50"/>
        <GridViewColumn Header="Name" this:ListTable.AutoSize="true"/>
        <GridViewColumn Header="Delete" Width="60"/>
    </GridView>




    SizeChanged event handler for the ListView:

    Code Block

            private void _listView_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                // Only relevant to grid views
                if (!(_listView.View is GridView))
                    return;

                GridView grid = _listView.View as GridView;

                // Only relevant for width
                if (!e.WidthChanged)
                    return;

                // Get all AutoSize columns
                List<GridViewColumn> columns = new List<GridViewColumn>();
                double specifiedWidth = 0;
                foreach (GridViewColumn col in grid.Columns)
                {
                    if ((bool)col.GetValue(AutoSizeProperty))
                        columns.Add(col);
                    else
                        specifiedWidth += col.ActualWidth;
                }

                // Give them a fair share of the remaining space
                foreach (GridViewColumn col in columns)
                {
                    double newWidth = (_listView.ActualWidth - specifiedWidth) / columns.Count;
                    if (newWidth >= 0)
                        col.Width = newWidth;
                }
            }



    Sunday, October 21, 2007 10:10 AM
  • Hi Jan
     
    Check out my approach:
     
     
    Jani
     
    Wednesday, April 09, 2008 7:32 AM
  •  

     

    I found a way to solve this here.

     

    http://www.ontheblog.net/CMS/Home/tabid/36/EntryID/37/Default.aspx

     

    Detail and Source

    Friday, April 18, 2008 1:20 PM
  • Here is my "quicky" to this issue:

    <!-- Xaml -->
    <ListView
     ItemsSource="{Binding <Source and Path Values>, NotifyOnTargetUpdated=True}"
     TargetUpdated="courseView_TargetUpdated"
     >
     ...
    </ListView>

    // Code

    void courseView_TargetUpdated(object sender, DataTransferEventArgs e)
    {
      var view = courseView.View as GridView;
      AutoResizeGridViewColumns(view);
    }

    static void AutoResizeGridViewColumns(GridView view)
    {
      if (view == null || view.Columns.Count < 1) return;
      // Simulates column auto sizing
      foreach (var column in view.Columns)
      {
     // Forcing change
     if (double.IsNaN(column.Width))
       column.Width = 1;
     column.Width = double.NaN;
      }
    }

    This auto-resizing implementation occurrs whn the data is updated. The static method could be called for any other type of event in the window, or in a customized listView, or even a custom GridViewColumn [Just the "Forcing change" code].

    Andres


    Andres Olivares
    • Proposed as answer by EternalCoder Thursday, January 27, 2011 6:50 AM
    Wednesday, December 24, 2008 4:58 AM
  • This works perfectly. After messing around with behaviors and other junk for hours, this is the only thing that actually works. Thanks!
    Wednesday, July 25, 2012 9:36 PM
  • The perfect solution for my problem, thank you very much!!!!

    Here is my "quicky" to this issue:

    <!-- Xaml -->
    <ListView
     ItemsSource="{Binding <Source and Path Values>, NotifyOnTargetUpdated=True}"
     TargetUpdated="courseView_TargetUpdated"
     >
     ...
    </ListView>

    // Code

    void courseView_TargetUpdated(object sender, DataTransferEventArgs e)
    {
      var view = courseView.View as GridView;
      AutoResizeGridViewColumns(view);
    }

    static void AutoResizeGridViewColumns(GridView view)
    {
      if (view == null || view.Columns.Count < 1) return;
      // Simulates column auto sizing
      foreach (var column in view.Columns)
      {
     // Forcing change
     if (double.IsNaN(column.Width))
       column.Width = 1;
     column.Width = double.NaN;
      }
    }

    This auto-resizing implementation occurrs whn the data is updated. The static method could be called for any other type of event in the window, or in a customized listView, or even a custom GridViewColumn [Just the "Forcing change" code].

    Andres


    Andres Olivares


    Wednesday, March 19, 2014 11:54 AM