Freitag, 11. Mai 2012

Seting Visibility on a GridViewColum of a ListView in WPF

There are two different ways how the Visibility of a GridViewColumn can be set.

1. With attached properties
2. Extending the GridViewColumn

In the attached property version, we save the original width of the column in another attached property, whenever the visibility is set to something else than Visible. After that we set the Width to 0.
This way the column disappears.

When resetting the Visibility to visible, we retrieve the original saved width and restore it to the Width property again.

public class GridViewColumnVisibilityManager
{
    public static Visibility GetVisibility(DependencyObject o)
    {
        return (Visibility)o.GetValue(VisibilityProperty);
    }

    public static void SetVisibility(DependencyObject obj, Visibility value)
    {
        obj.SetValue(VisibilityProperty, value);
    }

    public static readonly DependencyProperty VisibilityProperty =
        DependencyProperty.RegisterAttached("Visibility", typeof(Visibility),
        typeof(GridViewColumnVisibilityManager),
        new FrameworkPropertyMetadata(Visibility.Visible, 
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        new PropertyChangedCallback(OnVisibilityPropertyChanged)));

    private static void OnVisibilityPropertyChanged(DependencyObject d, 
                                     DependencyPropertyChangedEventArgs e)
    {
        var column = d as GridViewColumn;
        if (column != null)
        {
            var visibility = GetVisibility(column);
            if (visibility == Visibility.Visible)
            {
                // set the with back to the original
                column.Width = GetVisibleWidth(column);
            }
            else
            {
                // store the original width
                SetVisibleWidth(column, column.Width);
                // set the column width to 0 to hide it
                column.Width = 0.0;
            }
        }
    }

    public static double GetVisibleWidth(DependencyObject obj)
    {
        return (double)obj.GetValue(VisibleWidthProperty);
    }

    public static void SetVisibleWidth(DependencyObject obj, double value)
    {
        obj.SetValue(VisibleWidthProperty, value);
    }

    /// <summary>
    /// dpenendency property that stores the last visible width
    /// whenever the visibility changes this propert is used to set or get the width
    /// </summary>
    public static readonly DependencyProperty VisibleWidthProperty =
        DependencyProperty.RegisterAttached("VisibleWidth", 
                typeof(double), 
                typeof(GridViewColumnVisibilityManager), 
                new UIPropertyMetadata(double.NaN));

}

<ListView ItemsSource="{Binding DataObjects}" Grid.Column="1" >
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" 
                     foo:GridViewColumnVisibilityManager.Visibility="{Binding IsVisible, Converter={StaticResource boolToVis}}"/>
                <GridViewColumn Header="Vorname" DisplayMemberBinding="{Binding Vorname}"/>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>


The extension works the same way except that we can use a variable to store the original width instead of an attached property.

public class GridViewColumnExt : GridViewColumn
{
    public Visibility Visibility
    {
        get
        {
            return (Visibility)GetValue(VisibilityProperty);
        }
        set
        {
            SetValue(VisibilityProperty, value);
        }
    }

    public static readonly DependencyProperty VisibilityProperty =
        DependencyProperty.Register("Visibility", typeof(Visibility), 
        typeof(GridViewColumnExt),
        new FrameworkPropertyMetadata(Visibility.Visible, 
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        new PropertyChangedCallback(OnVisibilityPropertyChanged)));

    private static void OnVisibilityPropertyChanged(DependencyObject d, 
                                  DependencyPropertyChangedEventArgs e)
    {
        var column = d as GridViewColumnExt;
        if (column != null)
        {
            column.OnVisibilityChanged((Visibility)e.NewValue);
        }
    }

    private void OnVisibilityChanged(Visibility visibility)
    {
        if (visibility == Visibility.Visible)
        {
            Width = _visibleWidth;
        }
        else
        {
            _visibleWidth = Width;
            Width = 0.0;
        }
    }

    double _visibleWidth;
}

<ListView ItemsSource="{Binding DataObjects}" Grid.Column="1" >
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <c:GridViewColumnExt Header="Name" DisplayMemberBinding="{Binding Name}" 
                     Visibility="{Binding IsVisible, Converter={StaticResource boolToVis}}"/>
                <GridViewColumn Header="Vorname" DisplayMemberBinding="{Binding Vorname}"/>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

Keine Kommentare: