web-dev-qa-db-fra.com

Lier la visibilité de la colonne de la grille de données MVVM

.Net 3.5

Je sais que les colonnes n'héritent pas du datacontext et en lisant d'autres articles, j'ai pensé que cela fonctionnerait:

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

Mais bien sûr que non. La fenêtre de sortie ne se plaint pas, il semble que la ressource que j'ai trouvée mais la propriété viewmodel soit plus récente appelée.

Voici la DG entière:

<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>

J'ai lu à peu près toutes les solutions à ce problème et rien ne fonctionne ..

49
jrb

DataGridColumns ne font pas partie de l'arborescence visuelle et ne sont donc pas connectés au contexte de données de DataGrid.

Pour eux connectez ensemble, utilisez l'approche des éléments proxy comme ceci ...

  1. Ajoutez un proxy FrameworkElement dans le Resources de votre panneau ancêtre.
  2. L'héberger dans un ContentControl invisible lié à son Content.
  3. Utilisez ce ProxyElement comme StaticResource pour la source de contexte de données dans votre liaison de visibilité.

    <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> 
    

Outre DataGridColumn, l'approche ci-dessus fonctionne également très bien pour connecter DataContext à Popups et ContextMenus (c'est-à-dire tout élément qui n'est pas connecté à l'arborescence visuelle) .

tilisateurs Silverlight

Malheureusement, la définition du contenu des contrôles de contenu avec des éléments de structure n'est pas autorisée dans Silverlight. La solution de contournement serait donc (ce n'est qu'un code d'orientation pour Silverlight) ...

  1. Remplacez la ressource d'élément d'infrastructure par quelque chose de léger comme un Textblock. (Silverlight ne permet pas de spécifier une ressource statique de type FrameworkElement.)

    <StackPanel.Resources>
        <TextBlock x:Key="MyTextBlock" />
    
  2. Écrivez une propriété attachée pour maintenir le bloc de texte contre le contrôle de contenu.

    <ContentControl Visibility="Collapsed" 
                    local:MyAttachedBehavior.ProxyElement="{StaticResource MyTextBlock}" />
    
  3. Dans la propriété de dépendance attachée, le gestionnaire d'événements modifié, définissez le lien du contexte de données du contrôle de contenu aux blocs de texte.

     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);
           }
     }
    

Ainsi, de cette façon, le bloc de texte peut ne pas être connecté à l'arborescence visuelle mais probablement sera au courant des changements de contexte des données.

J'espère que cela t'aides.

102
WPF-it