Bind datagrid MVVM column visibility display

.Net 3.5

I know that columns do not inherit the datacontext and, while reading other posts, I thought this would work:

Visibility="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(FrameworkElement.DataContext).IsColumnNameVisible, Converter={StaticResource boolToVisConverter}}" 

However, of course, this is not so. The output window does not complain, it seems that the resource I found, but the viewmodel property, is called by a newer one.

This is the whole DG:

 <tk:DataGrid VirtualizingStackPanel.IsVirtualizing="False" Grid.Column="0" AlternationCount="2" AreRowDetailsFrozen="True" AutoGenerateColumns="False" Background="Transparent" BorderThickness="0" CanUserAddRows="False" CanUserReorderColumns="True" CanUserResizeRows="False" GridLinesVisibility="None" ItemsSource="{Binding Employees}" SelectionMode="Single" ColumnHeaderStyle="{StaticResource columnHeaderStyle}" RowHeaderStyle="{StaticResource rowHeaderStyle}" CellStyle="{StaticResource cellStyle}" RowStyle="{StaticResource rowStyle}" ContextMenu="{StaticResource columnHeaderContextMenu}"> <tk:DataGrid.Resources> <ContextMenu x:Key="columnHeaderContextMenu" ItemsSource="{Binding ColumnHeaderContextMenuItems}" /> <Style TargetType="{x:Type ScrollBar}"> <Setter Property="Background" Value="Transparent"/> </Style> <Style TargetType="{x:Type tk:DataGridColumnHeader}"> <Setter Property="Background" Value="Transparent"/> </Style> </tk:DataGrid.Resources> <tk:DataGrid.Triggers> <EventTrigger RoutedEvent="tk:DataGridRow.MouseDoubleClick"> <EventTrigger.Actions> <BeginStoryboard Storyboard="{StaticResource showDetailGrid}"/> </EventTrigger.Actions> </EventTrigger> </tk:DataGrid.Triggers> <tk:DataGrid.Columns> <tk:DataGridTextColumn IsReadOnly="True" Header="test" Binding="{Binding Name, Mode=OneWay}" Visibility="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(FrameworkElement.DataContext).IsColumnNameVisible, Converter={StaticResource boolToVisConverter}}" /> </tk:DataGrid.Columns> </tk:DataGrid> 

I read almost all the solutions to this problem and nothing works.

+44
c # wpf xaml wpftoolkit
Oct 10 '11 at 10:12
source share
1 answer

DataGridColumn are not part of the visual tree, so they are not related to the DataGrid data context.

For them connect together, use a proxy approach similar to this ...

  • Add the FrameworkElement proxy to the Resources ancestor panel.
  • Connect it to an invisible ContentControl bound to its Content .
  • Use this ProxyElement as a StaticResource for the data context source in your visibility binding.

     <StackPanel> <StackPanel.Resources> <local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/> </StackPanel.Resources> <ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"/> <DataGrid AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Visibility="{Binding DataContext.IsTextColumnVisibile, Source={StaticResource ProxyElement}, Converter={StaticResource BooleanToVisibilityConverter}}" Binding="{Binding Text}"/> </DataGrid.Columns> </DataGrid> </StackPanel> 

Besides the DataGridColumn , the above approach is great for connecting a DataContext to Popup and ContextMenu (i.e. to any element that is not connected to the visual tree).

Silverlight Users

Sadly configured content controls with any structure elements are not allowed in silverlight. So a workaround would be (this is just a hover code for silverlight) ...

  • Change the resource of the structure element to something lightweight like Textblock . (Silverlight does not allow you to specify a static resource of type FrameworkElement .)

     <StackPanel.Resources> <TextBlock x:Key="MyTextBlock" /> 
  • Write an attached property to hold the text block for the content control.

     <ContentControl Visibility="Collapsed" local:MyAttachedBehavior.ProxyElement="{StaticResource MyTextBlock}" /> 
  • In the dependent attribute of the dependent dependency processor, specify the data context binding of the content control to the text block.

      private static void OnProxyElementPropertyChanged( DependencyObject depObj, DependencyPropertyChangedEventArgs e) { if (depObj is ContentControl && e.NewValue is TextBlock) { var binding = new Binding("DataContext"); binding.Source = depObj; binding.Mode = OneWay; BindingOperations.SetBinding( (TextBlock)e.NewValue, TextBlock.DataContextProperty, binding); } } 

Thus, the text block cannot be associated with the visual tree, but it will probably know the changes in the data context.

Hope this helps.

+94
10 Oct '11 at 10:40
source share



All Articles