I am trying to control the visibility of a column using a checkbox (this is in WPF 4.0).
Here is a snippet of my XAML:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>
<CheckBox x:Name="GeneralDetailsVisible" Content="General Details" Margin="5"/>
<DataGridTextColumn Header="Crew"
Binding="{Binding Path=Crew}"
Visibility="{Binding ElementName=GeneralDetailsVisible,
Converter={StaticResource BoolToVisConverter},
Path=IsChecked}">
</DataGridTextColumn>
Now I know the BooleanToVisibilityConverter converter is working as I bound it to a text block and I can see the values I am expecting. If I enter the values by hand into the columns visibility property it works. But not when I bind it. What am I doing wrong?
Answer:
Quartermeister pointed me to the answer. The page he pointed to is a bit misleading as the code listed on the post does not work and you must look at the sample code.
Here is my final, working code, for anyone else who runs into this problem:
Converter to turn our ViewModels bool property into the correct Visibility value for our column attribute.
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>
Bind the checkbox to the ViewModels property that will control the columns visibiity.
<CheckBox
x:Name="DetailsVisible"
Content="Show Details"
IsChecked="{Binding Path=DisplayDetails}" />
Then bind Visibility to the ViewModels DisplayDetails property. Notice that it is the columns own DataContext that is bound to.
<DataGridTextColumn
Header="Reliability"
Binding="{Binding Path=Reliability}"
Visibility="{Binding (FrameworkElement.DataContext).DisplayDetails,
RelativeSource={x:Static RelativeSource.Self},
Converter={StaticResource BoolToVisConverter}}">
</DataGridTextColumn>
Add the following code to your project, this allows the catching of the change in a DataGrids DataContext.
FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid),
new FrameworkPropertyMetadata
(null, FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(OnDataContextChanged)));
Then whenever your DataGrids DataContext is changed we update all the attached DataGridColumsn with the new DataContext.
public static void OnDataContextChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
DataGrid grid = d as DataGrid;
if (grid != null)
{
foreach (DataGridColumn col in grid.Columns)
{
col.SetValue(FrameworkElement.DataContextProperty, e.NewValue);
}
}
}
One Gotcha to look out for. If you add your DataContext to your page like so:
<Window.DataContext>
<vm:WeaponListViewModel />
</Window.DataContext>
Then the above function will be called before your DataGrid has any columns!
I got around this by manually attaching my DataConext in code behind after the window was created.
IMO using x:Name
, x:Reference
and Source
is simpler:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<CheckBox x:Name="showImperial" Content="Show Details" />
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="TOV (Bls)"
Width="80"
Binding="{Binding TOVBarrels}"
Visibility="{Binding Source={x:Reference showImperial},
Path=IsChecked,
Converter={StaticResource BooleanToVisibilityConverter}}"/>
</DataGrid.Columns>
</DataGrid>
See this answer: Bind visibility to checkable menu item shows error "Service provider is missing the INameResolver service" in WPF
The problem is that the DataGrid columns are not part of the visual tree, so they cannot use bindings. (The "Binding" property is actually a normal property of type Binding, not a dependency property. It applies that binding object to the cells, which are part of the visual tree.)
Here is a link to a blog that has a workaround and demonstrates binding the visibility of a column to a check box: http://blogs.msdn.com/b/jaimer/archive/2008/11/22/forwarding-the-datagrid-s-datacontext-to-its-columns.aspx
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