I have the following WPF sample program:
Xaml:
<Window x:Class="AncestorArie.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <BooleanToVisibilityConverter x:Key="BoolToVis" /> </Window.Resources> <Grid> <DataGrid AutoGenerateColumns="False" Name="Blumen" ItemsSource="{Binding Leaves}"> <DataGrid.Columns> <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}}" /> </DataGrid.Columns> </DataGrid> </Grid> </Window>
Code behind:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Flowers rose = new Flowers(); rose.Leaves = new ObservableCollection<Leaf>(); rose.Flag = false; Leaf L1 = new Leaf(); L1.Color = "rot"; L1.Size = 3; rose.Leaves.Add(L1); Leaf L2 = new Leaf(); L2.Color = "gelb"; L2.Size = 2; rose.Leaves.Add(L2); 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 Flag
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 Visibility
attribute?
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" ...> <Window.Resources> <DataGridTextColumn x:Key="ThatPeskyColumn" Binding="{Binding Size}" Visibility="{Binding DataContext.Flag, Source={x:Reference _window}, Converter={StaticResource BoolToVis}}"/> </Window.Resources> <!-- ... --> <DataGrid AutoGenerateColumns="False" Name="Blumen" ItemsSource="{Binding Leaves}"> <DataGrid.Columns> <StaticResource ResourceKey="ThatPeskyColumn"/> <!-- ... -->
Great fun.
I would prefer a more elegant approach which involves using a Freezable
.
<Window.Resources> <DiscreteObjectKeyFrame x:Key="FlagKey" Value="{Binding Flag}"/> </Window.Resources> <DataGridTextColumn ... Visibility="{Binding Value, Source={StaticResource FlagKey}, ...}" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With