2009-04-08 7 views
29

J'ai l'objet suivant dans App.xamlWPF: comment masquer GridViewColumn en utilisant XAML?

<Application.Resources> 
     <ResourceDictionary> 
      <GridView x:Key="myGridView" x:Shared="false"> 
          <GridViewColumn Header="Created" DisplayMemberBinding="{Binding Path=Created}"/> 

... more code ... 

Et j'utilise ce point de vue du réseau à plusieurs endroits. Exemple:

<ListView x:Name="detailList" View="{StaticResource myGridView}" ...> 

Dans l'un des usages (comme Detaillist ci-dessus), je voudrais cacher la colonne créée, éventuellement à l'aide XAML?

Des idées?

Répondre

0

Je suggérerais d'utiliser une propriété personnalisée (ou d'en détourner une existante) sur le parent, puis d'utiliser un style personnalisé sur le gridviewcolumnheader pour faire référence à cette propriété ancêtre. Comme ceci:

<Window.Resources> 
    <Style TargetType="{x:Type GridViewColumnHeader}"> 
     <Setter Property="Visibility" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=Tag}"/> 
    </Style> 
    <GridView x:Key="myGridView" x:Shared="false">        
     <GridViewColumn Header="Created" DisplayMemberBinding="{Binding Path=Created}"/>  
    </GridView> 
</Window.Resources> 
<Grid x:Name="LayoutRoot"> 
    <StackPanel> 
     <ListView x:Name="detailList" View="{StaticResource myGridView}"/> 
     <ListView x:Name="detailListHide" Tag="{x:Static Member=Visibility.Hidden}" View="{StaticResource myGridView}"/> 
    </StackPanel> 
</Grid> 
+0

Je viens de réaliser que cela ne cache l'en-tête de colonne, et qui est sans doute pas ce que vous vouliez faire. Je ne trouve aucun moyen de masquer toute la colonne avec juste xaml sauf de faire une seconde grille. –

+3

Définir une largeur de GridViewColumn à 0 le cachera efficacement. –

+1

J'ai essayé, mais ce n'est pas vraiment parti. Vous pouvez toujours l'étendre avec la souris. –

5

Vous le mieux est sans doute de créer un contrôle personnalisé en héritant de la classe GridView, en ajoutant les colonnes nécessaires, et d'exposer une propriété significative pour afficher/masquer une colonne particulière. Votre classe GridView personnalisée pourrait ressembler à ceci:

using System; 
using System.Windows.Controls; 

namespace MyProject.CustomControls 
{ 
    public class CustomGridView : GridView 
    { 
     private GridViewColumn _fixedColumn; 
     private GridViewColumn _optionalColumn; 

     public CustomGridView() 
     { 
      this._fixedColumn = new GridViewColumn() { Header = "Fixed Column" }; 
      this._optionalColumn = new GridViewColumn() { Header = "Optional Column" }; 

      this.Columns.Add(_fixedColumn); 
      this.Columns.Add(_optionalColumn); 
     } 

     public bool ShowOptionalColumn 
     { 
      get { return _optionalColumn.Width > 0; } 
      set 
      { 
       // When 'False' hides the entire column 
       // otherwise its width will be set to 'Auto' 
       _optionalColumn.Width = (!value) ? 0 : Double.NaN; 
      } 
     } 

    } 
} 

Ensuite, vous pouvez simplement définir cette propriété de XAML comme dans cet exemple:

<Window x:Class="WpfApplication1.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:cc="clr-namespace:MyProject.CustomControls" 
     Title="Window1" 
     Height="300" 
     Width="300"> 
    <StackPanel> 
     <ListView> 
      <ListView.View> 
       <cc:CustomGridView ShowOptionalColumn="False" /> 
      </ListView.View> 
     </ListView> 

     <ListView> 
      <ListView.View> 
       <cc:CustomGridView ShowOptionalColumn="True" /> 
      </ListView.View> 
     </ListView> 
    </StackPanel> 
</Window> 

En option, vous pouvez faire le « CustomGridView.ShowOptionalColumn » a DependencyProperty pour pouvoir l'utiliser comme cible de liaison.

4

Taken de here

<ListView Grid.Column="1" Grid.Row="1" Name="FicheList" > 
      <ListView.Resources> 
       <ResourceDictionary> 
        <Style x:Key="hiddenStyle" TargetType="GridViewColumnHeader"> 
         <Setter Property="Visibility" Value="Collapsed"/> 
        </Style> 
       </ResourceDictionary> 
      </ListView.Resources> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn DisplayMemberBinding="{Binding Code}" Header="Code" Width="0" HeaderContainerStyle="{StaticResource hiddenStyle}" /> 
        <GridViewColumn DisplayMemberBinding="{Binding FicheTitle}" Header="Title" Width="100" /> 
        <GridViewColumn DisplayMemberBinding="{Binding CategoryName}" Header="Category" Width="100" /> 
        <GridViewColumn DisplayMemberBinding="{Binding UpdateDate}" Header="Update Date" Width="100" /> 

       </GridView> 
      </ListView.View> 
     </ListView> 
+1

Nice. Masque l'en-tête uniquement, laissant les cellules visibles. –

+2

Pas ce que le PO demandait, mais bon à savoir. (Personnellement, j'aimerais que les colonnes soient vraiment minces, donc il est toujours possible de redimensionner les colonnes) – Qwertie

17

En fait, je trouve la solution la plus simple est via les propriétés attachées:

public class GridViewColumnVisibilityManager 
{  
    static void UpdateListView(ListView lv) 
    { 
     GridView gridview = lv.View as GridView; 
     if (gridview == null || gridview.Columns == null) return; 
     List<GridViewColumn> toRemove = new List<GridViewColumn>(); 
     foreach (GridViewColumn gc in gridview.Columns) 
     { 
      if (GetIsVisible(gc) == false) 
      { 
       toRemove.Add(gc); 
      } 
     } 
     foreach (GridViewColumn gc in toRemove) 
     { 
      gridview.Columns.Remove(gc); 
     } 
    } 

    public static bool GetIsVisible(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsVisibleProperty); 
    } 

    public static void SetIsVisible(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsVisibleProperty, value); 
    } 

    public static readonly DependencyProperty IsVisibleProperty = 
     DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(true)); 


    public static bool GetEnabled(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(EnabledProperty); 
    } 

    public static void SetEnabled(DependencyObject obj, bool value) 
    { 
     obj.SetValue(EnabledProperty, value); 
    } 

    public static readonly DependencyProperty EnabledProperty = 
     DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(false, 
      new PropertyChangedCallback(OnEnabledChanged))); 

     private static void OnEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     ListView view = obj as ListView; 
     if (view != null) 
     { 
      bool enabled = (bool)e.NewValue; 
      if (enabled) 
      { 
       view.Loaded += (sender, e2) => 
       { 
        UpdateListView((ListView)sender); 
       }; 
       view.TargetUpdated += (sender, e2) => 
       { 
        UpdateListView((ListView)sender); 
       }; 
       view.DataContextChanged += (sender, e2) => 
       { 
        UpdateListView((ListView)sender); 
       }; 
      } 
     } 
    } 
} 

Ensuite, il peut être utilisé comme ceci:

<ListView foo:GridViewColumnVisibilityManager.Enabled="True"> 
... 
<GridViewColumn Header="Status" foo:GridViewColumnVisibilityManager.IsVisible="{Binding ShowStatusColumn}"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> ... 
+1

mon implémentation s'attend à ce que la visibilité d'une colonne soit statique pour une charge - si vous pensez que cela changera, vous devrez peut-être corriger UpdateListView() pour faire quelque chose d'autre à cacher et afficher la colonne (Width = 0). –

+0

C'est la meilleure solution que j'ai trouvé jusqu'ici, et j'ai réussi à l'obtenir pour travailler avec le changement dynamique de la propriété Visibile. Vois ma réponse. C'est particulièrement utile si vous voulez cacher par défaut et plus tard afficher la colonne si nécessaire. – surfen

+0

Cette solution ne fonctionne pas pour moi. Quand j'ai débogué, j'ai découvert que la méthode UpdateListView est appelée en premier et que la valeur de la propriété IsVisible est obtenue après. Je suppose que c'est une raison dans mon cas mais je ne sais pas pourquoi? Quelqu'un pourrait-il expliquer pourquoi cela peut arriver? – Pegieo

1

Cette c'est mon code, ça marche très bien dans mon projet. si vous n'aimez pas ajouter du code externe.

/// <summary> 
    /// show/hide datagrid column 
    /// </summary> 
    /// <param name="datagrid"></param> 
    /// <param name="header"></param> 
    private void ToggleDataGridColumnsVisible() 
    { 
     if (IsNeedToShowHideColumn()) 
     { 
      foreach (GridViewColumn column in ((GridView)(this.ListView1.View)).Columns) 
      { 
       GridViewColumnHeader header = column.Header as GridViewColumnHeader; 
       if (header != null) 
       { 
        string headerstring = header.Tag.ToString(); 

        if (!IsAllWaysShowingHeader(headerstring)) 
        { 
         if (IsShowingHeader()) 
         { 

         } 
         else 
         { 
          //hide it 
          header.Template = null; 
          column.CellTemplate = null; 
          column.Width = 0; 
         } 
        } 
       } 

      } 

     } 
    } 
12

Sur la base de la réponse de Ben McMillan, mais soutient le changement dynamique de la propriété visible. J'ai encore simplifié sa solution en supprimant la propriété IsEnabled.

public class GridViewColumnVisibilityManager 
{ 
    static Dictionary<GridViewColumn, double> originalColumnWidths = new Dictionary<GridViewColumn, double>(); 

    public static bool GetIsVisible(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsVisibleProperty); 
    } 

    public static void SetIsVisible(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsVisibleProperty, value); 
    } 

    public static readonly DependencyProperty IsVisibleProperty = 
     DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(GridViewColumnVisibilityManager), new UIPropertyMetadata(true, OnIsVisibleChanged)); 

    private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     GridViewColumn gc = d as GridViewColumn; 
     if (gc == null) 
      return; 

     if (GetIsVisible(gc) == false) 
     { 
      originalColumnWidths[gc] = gc.Width; 
      gc.Width = 0; 
     } 
     else 
     { 
      if (gc.Width == 0) 
       gc.Width = originalColumnWidths[gc]; 
     } 
    } 
} 
+1

Fonctionne comme un charme. Je vous remercie ! – Olwaro

+0

Brillant! Merci –

+0

Cela ne fuira pas la mémoire? Vous stockez le contrôle lui-même dans un dictionnaire statique ... – Rashack

0

In a small utility I wrote, J'ai une vue de liste où l'utilisateur peut cacher/montrer quelques colonnes. Il n'y a pas de propriété Visibility sur les colonnes, j'ai donc décidé de mettre la largeur des colonnes cachées à zéro. Pas idéal, car l'utilisateur peut encore les redimensionner et les rendre visibles à nouveau.

Quoi qu'il en soit, pour ce faire, je:

<GridViewColumn.Width> 
    <MultiBinding Converter="{StaticResource WidthConverter}" Mode="TwoWay"> 
     <Binding Path="ThreadIdColumnWidth" Mode="TwoWay" /> 
     <Binding Path="IsThreadIdShown" /> 
    </MultiBinding> 
</GridViewColumn.Width> 

IsThreadIdShown est lié à une case à cocher sur la barre d'outils. et le convertisseur multi-valeur est la suivante:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { 
    if (values.Length != 2) { 
     return null; 
    } 

    object o0 = values[0]; 
    object o1 = values[1]; 

    if (! (o1 is bool)) { 
     return o0; 
    } 
    bool toBeDisplayed = (bool) o1; 
    if (! toBeDisplayed) { 
     return 0.0; 
    } 

    if (! (o0 is double)) { 
     return 0; 
    } 

    return (double) o0; 
} 

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { 

    return new object[] { (double)value, Binding.DoNothing }; 
} 
0

Cela fonctionne pour moi
besoin de lier la visibilité tant sur l'en-tête et le contenu
Dans ce cas, il est à la fin, donc je ne vous inquiétez pas a propos de la largeur
mais l'utilisateur ne soit pas un crochet de l'interface utilisateur pour réinitialiser la largeur, donc si vous définissez la largeur à zéro, il est allé

<GridViewColumn Width="60"> 
    <GridViewColumnHeader HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" 
          Visibility="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.CurUser.IsInRoleSysAdmin, Converter={StaticResource bvc}}"> 
     <TextBlock>WS<LineBreak/>Count</TextBlock> 
    </GridViewColumnHeader> 
    <GridViewColumn.CellTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding Path=WordScoreCount, StringFormat={}{0:N0}}" HorizontalAlignment="Right" 
         Visibility="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.CurUser.IsInRoleSysAdmin, Converter={StaticResource bvc}}"/> 
     </DataTemplate> 
    </GridViewColumn.CellTemplate> 
</GridViewColumn> 
0

J'ai une solution beaucoup plus simple que d'utiliser un comportement attaché.

Tout ce que vous avez à faire est de lier la propriété Width de GridViewColumn à un booléen sur votre ViewModel. Ensuite, créez un convertisseur simple comme BooleanToWidthConverter qui prend un booléen et renvoie un double, zéro si c'est faux, x largeur si c'est vrai. J'espère que cela vous aidera et vous facilitera la vie.

XAML:

<GridViewColumn x:Name="MyHiddenGridViewColumn" 
       Width={Binding Path=IsColumnVisibleProperty, Converter={StaticResource BooleanToWidthConverter}}"> 
    <!-- GridViewColumn.HeaderTemplate etc. goes here. --> 
</GridViewColumn> 

Converter:

public class BooleanToWidthConverter : IValueConverter 
    { 
     private const double Column_Width = 40.0; 

     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      if (value != null && value != DependencyProperty.UnsetValue) 
      { 
       bool isVisible = (bool) value; 

       return isVisible ? Column_Width : 0; 
      } 
      return Column_Width; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
Questions connexes