Search code examples
wpflistviewgridviewgridviewcolumn

WPF: How to find ColumnHeader to my Column?


I'd like the users of my program to be able to decide for themselves, which columns they'd like to see in my ListView/GridView.

For that I created two attached properties for GridViewColumn, one is called IsColumnVisible of type Boolean (toggling visibility of the column on and off) and the other one is called LastWidth of type Double (holding the width of this column when it was last visible).

The property IsColumnVisible does have an OnChangedCallback.
When the property is set to False, I save the current width of the column in my property LastWidth and set the current width to 0.
When the property is set to True, I get the last width of the column from my property LastWidth and set the current width to that value.

This works so far, but with the flaw, that one can resize the hidden columns with the mouse to be visible again. So, if you have three columns and you hide the middle one, resizing the first one with the mouse ends up in making the second column visible again.

To get rid of that I wanted to set the IsEnabled state of the headers of the hidden columns to False and that's where the problem begins.

Let's say my columns are defined in XAML like this (columns 1 and 4 visible, columns 2 and 3 hidden):

<GridView AllowsColumnReorder="True">
    <GridViewColumn Header="Column 1" Width="50" DisplayMemberBinding="{Binding Column1}" local:GridViewColumnConfig.IsColumnVisible="True" />
    <GridViewColumn Header="Column 2" Width="50" DisplayMemberBinding="{Binding Column2}" local:GridViewColumnConfig.IsColumnVisible="False" />
    <GridViewColumn Header="Column 3" Width="50" DisplayMemberBinding="{Binding Column3}" local:GridViewColumnConfig.IsColumnVisible="False">
        <GridViewColumn.Header>
            <GridViewColumnHeader Content="Column 4" />
        </GridViewColumn.Header>
    </GridViewColumn>
    <GridViewColumn Header="Column 4" Width="50" DisplayMemberBinding="{Binding Column4}" local:GridViewColumnConfig.IsColumnVisible="True" />
</GridView>

Since the default value of my property IsColumnVisible is True, my OnChangedCallback of this property only runs for columns 2 and 3.

I have an object of type GridViewColumn in the OnChangedCallback and to be able to set the IsEnabled state of the column header I need to determine the GridViewColumnHeader of my GridViewColumn.
A GridViewColumn has a property Header of type Object. In case of column 2 this property contains the String "Column 2", in case of column 3 this property is Nothing.

Is there any way to get the header of my GridViewColumn as a GridViewColumnHeader object?

In case of column 2 I could create a GridViewColumnHeader object myself, set it's Content to the value of the Header property and then set the Header property to this object.
But I'd rather not do those changes if I don't have to.

In case of column 3 there already should be a GridViewColumnHeader object somewhere (since I defined it in XAML), but I can't find it.
I already tried to walk the Visual Tree, but since GridViewColumn is not a Visual or a Visual3D, that's not possible.

Any ideas? Thank you.


Solution

  • Is there any way to get the header of my GridViewColumn as a GridViewColumnHeader object?

    The easiest way to do this would be to set the value of your custom attached property after you have set the value of the Header property.

    You could do this if you switch to using element syntax:

    <GridViewColumn Width="50" DisplayMemberBinding="{Binding Column3}" xmlns:sys="clr-namespace:System;assembly=mscorlib">
        <GridViewColumn.Header>
            <GridViewColumnHeader Content="Column 4" />
        </GridViewColumn.Header>
        <local:GridViewColumnConfig.IsColumnVisible>
            <sys:Boolean>False</sys:Boolean>
        </local:GridViewColumnConfig.IsColumnVisible>
    </GridViewColumn>
    

    Then you will be able to simply cast the Header property to a GridViewColumnHeader in your PropertyChangedCallback:

    Private Shared Sub OnPropertyChanged(d As GridViewColumn, e As DependencyPropertyChangedEventArgs)
        Dim header = TryCast(d.Header, GridViewColumnHeader)
        '...
    End Sub