view raw
Hulda Hulda - 6 months ago 60
C# Question

How to hide wpf datagrid columns depending on a property

I have the following WPF sample program:


<Window x:Class="AncestorArie.MainWindow"
Title="MainWindow" Height="350" Width="525">
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataGrid AutoGenerateColumns="False" Name="Blumen"
ItemsSource="{Binding Leaves}">
<DataGridTextColumn Binding="{Binding Color}"
Header="Farbe" Width="160" />
<DataGridTextColumn Binding="{Binding Size}"
Header="Größe" Width="60"
Visibility="{Binding Path=DataContext.Flag,
RelativeSource={RelativeSource Findancestor,
AncestorType={x:Type Window}},
Converter={StaticResource BoolToVis}}" />

Code behind:

public partial class MainWindow : Window
public MainWindow()
Flowers rose = new Flowers();
rose.Leaves = new ObservableCollection<Leaf>();

rose.Flag = false;

Leaf L1 = new Leaf();
L1.Color = "rot";
L1.Size = 3;

Leaf L2 = new Leaf();
L2.Color = "gelb";
L2.Size = 2;

this.DataContext = rose;

And the model classes are:

public class Leaf
public string Color { get; set; }
public int Size { get; set; }

public class Flowers
public bool Flag { get; set; }
public ObservableCollection<Leaf> Leaves { get; set; }

As you can see, I want to hide the 2nd datagrid column, if the
property is set to false. But it doesn't work. I get the following binding error in the Visual Studio Output window:

System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'RelativeSource FindAncestor,
AncestorType='System.Windows.Window', AncestorLevel='1''.
BindingExpression:Path=DataContext.Flag; DataItem=null; target element
is 'DataGridTextColumn' (HashCode=44856655); target property is
'Visibility' (type 'Visibility')

What is wrong in my code concerning the


A column in a datagrid is an abstract object which does not appear in the visual tree, thus you cannot use RelativeSource-binding, ElementName will not work either since it will not find a governing FrameworkContentElement so you are in kind of a bind.

One way that works is via Source and x:Reference, for that you will need to name your window and move the column to its resources to avoid a cyclical dependency error:

<Window Name="_window" ...>
        <DataGridTextColumn x:Key="ThatPeskyColumn"
                            Binding="{Binding Size}"
                            Visibility="{Binding DataContext.Flag, Source={x:Reference _window}, Converter={StaticResource BoolToVis}}"/>
    <!-- ... -->
        <DataGrid AutoGenerateColumns="False" Name="Blumen" 
                  ItemsSource="{Binding Leaves}">
                <StaticResource ResourceKey="ThatPeskyColumn"/>
                <!-- ... -->

Great fun.