Binding Visibility for DataGridColumn in WPF

datagrid, visibility, wpf, xaml

Solution

First of all, `DataGridTextColumn` (or any other supported dataGrid column) does not lie in the Visual tree of the `DataGrid`. Hence, by default it doesn't inherit the `DataContext` of the `DataGrid`. However, it works for `Binding` DP only and for no other DP's on DataGridColumn.

Since they don't lie in the same VisualTree, any attempt to get the `DataContext` using `RelativeSource` won't work as well because `DataGridTextColumn` is unable to traverse up to the `DataGrid`.

There are two other ways to achieve this though:

First using a `Freezable` class. `Freezable` objects can inherit the DataContext even when they’re not in the visual or logical tree –We can take advantage of that.

First, create a class inheriting from `Freezable` and `Data` DP which we can use to bind in XAML:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object),
                                     typeof(BindingProxy));
}

Now, add an instance of it in DataGrid resources so that it can inherit the DataGrid's DataContext and can bind with its Data DP:

    <DataGrid>
        <DataGrid.Resources>
            <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Visibility="{Binding Data.MyColumnVisibility,
                                                Source={StaticResource proxy}}"/>
        </DataGrid.Columns>
    </DataGrid>

Second, you can refer to any UI element in XAML using `ElementName` or `x:Reference`. However, `ElementName` works only in the same visual tree, whereas x:Reference doesn't have such constraints.

So, we can use that as well to our advantage. Create a dummy `FrameworkElement` in XAML with Visibility set to `collapsed`. The FrameworkElement will inherit the DataContext from its parent container, which can be a Window or UserControl.

And can use that in DataGrid:

    <FrameworkElement x:Name="dummyElement" Visibility="Collapsed"/>
    <DataGrid>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Test"
                                Binding="{Binding Name}"
                                Visibility="{Binding DataContext.IsEnable,
                                          Source={x:Reference dummyElement}}"/>
        </DataGrid.Columns>
    </DataGrid>

Problem

How can I hide a column in a WPF `DataGrid` through a Binding? This is what I did: ``` <DataGridTextColumn Header="Column header" Binding="{Binding ColumnValue}" Width="100" ElementStyle="{StaticResource DataGridRightAlign}" Visibility="{Binding MyColumnVisibility}" /> ``` And this is what I got (besides the column still visible): System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=MyColumnVisibility; DataItem=null; target element is 'DataGridTextColumn' (HashCode=1460142); target property is 'Visibility' (type 'Visibility') How to fix the binding?

Original source

Related problems