2009-10-13 10 views
7

Desidero controllare la visibilità della colonna DataGrid tramite un ContextMenu disponibile all'utente facendo clic con il pulsante destro del mouse sull'intestazione della colonna. Il ContextMenu visualizza i nomi di tutte le colonne disponibili. Sto usando il modello di progettazione MVVM.WGrf DataGrid: Binding DataGridColumn visibilità a ContextMenu MenuItems IsChecked (MVVM)

La mia domanda è: Come faccio lego 's la DataGridColumnVisibility struttura al IsChecked proprietà di un MenuItem situato nel ContextMenu.

Alcuni codice mockup:

<UserControl.Resources>   
    <ContextMenu x:Key="ColumnHeaderContextMenu"> 
     <MenuItem Header="Menu Item..1" IsCheckable="True" /> 
    </ContextMenu> 
    <Style x:Key="ColumnHeaderStyle" 
      TargetType="{x:Type toolkit:DataGridColumnHeader}"> 
     <Setter Property="ContextMenu" 
       Value="{StaticResource ColumnHeaderContextMenu}" /> 
    </Style> 
    <BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" /> 
</UserControl.Resources> 

... flaf flaf flaf

<toolkit:DataGrid x:Name="MyGrid" AutoGenerateColumns="False" 
    ItemsSource="{Binding MyCollection, Mode=Default}" 
    EnableColumnVirtualization="True" IsReadOnly="True" 
    ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"> 
    <toolkit:DataGrid.Columns> 
     <toolkit:DataGridTextColumn Binding="{Binding Path=MyEntry}" 
      Header="MyEntry" Visibility="{Binding IsChecked, Converter= 
       {StaticResource booleanToVisibilityConverter}.... /> 
    </toolkit:DataGrid.Columns>  
</toolkit:DataGrid> 

Se io sia poco chiaro per favore fatemelo sapere e cercherò di elaborare.

Cheers,

risposta

18

ho appena scritto un post sul blog su questo argomento. Consente a DataGridColumns di essere visualizzato o nascosto tramite un ContextMenu accessibile facendo clic con il pulsante destro del mouse su qualsiasi intestazione di colonna. Questa attività viene eseguita esclusivamente tramite le proprietà associate, pertanto è conforme a MVVM.

See blog post

+0

Basta guardarlo e sembra solido. Ti darei un voto ma mancava di 1 reputazione :) – Fubzot

+0

Questo ha funzionato magnificamente !! Roba impressionante. Ora ho bisogno di studiarlo in dettaglio una volta scaduta la mia scadenza :) – BloggerDude

+2

SO regole suggeriscono che il collegamento a un blog piuttosto che pubblicare il contenuto esplicito non è l'ideale. Puoi davvero rispondere alla Q qui? – Webreaper

-1

ho cercato di ge questo per legare al ContextMenu usando 'ElementName', ma alla fine, ha ottenuto il lavoro utilizzando Proprietà nella VM, ad esempio,

bool _isHidden; 
public bool IsHidden 
{ 
    get { return _isHidden; } 
    set 
    { 
    if (value != _isHidden) 
    { 
     _isHidden = value; 
     RaisePropertyChanged("IsHidden"); 
     RaisePropertyChanged("IsVisible"); 
    } 
    } 
} 

public Visibility IsVisible 
{ 
    get { return IsHidden ? Visibility.Hidden : Visibility.Visible; } 
} 

e nel XAML:

<Window.ContextMenu> 
    <ContextMenu> 
    <MenuItem Header="Hidden" IsCheckable="True" IsChecked="{Binding IsHidden}" /> 
    </ContextMenu> 
</Window.ContextMenu> 

<toolkit:DataGrid x:Name="MyGrid" AutoGenerateColumns="False" ItemsSource="{Binding MyCollection, Mode=Default}" EnableColumnVirtualization="True" IsReadOnly="True" ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"> 
    <toolkit:DataGrid.Columns> 
    <toolkit:DataGridTextColumn Binding="{Binding Path=MyEntry}" Header="MyEntry" Visibility="{Binding Path=IsVisible, Mode=OneWay}" /> 
    </toolkit:DataGrid.Columns> 
</toolkit:DataGrid> 
+0

Ciao Ian, potresti elaborarlo? Ho un datagrid che si lega alla raccolta. Voglio nascondere la colonna (visibilità) controllando la proprietà booleana. E.g Classe ContextClass {CollectionForGrid; È attivo; } Collego CollectionForGrid a Grid e voglio impostare visiblity di una colonna base sulla proprietà IsActive. – RockWorld

+0

@Rakesh - il mio miglior consiglio sarebbe di aprire una nuova domanda e io (insieme al resto della comunità SO) proverò a rispondere per voi :) – kiwipom

1

Ok, questo è stato piuttosto l'esercizio per un n00b WPF.

IanR grazie per il suggerimento Ho usato un simile aproach ma dosent ti accompagna fino in fondo.

Ecco quello che sono venuto su con se qualcuno può trovare un modo più coerente di farlo Io apprezzo qualsiasi commento:

impedimenti:

  1. DataGridColumnHeader non supporta un menu contestuale. Pertanto il menu di scelta rapida deve essere applicato come stile.

  2. Il menu di contesto ha il proprio datacontext, quindi dobbiamo usare findancestor per collegarlo al datacontext ViewModels.

  3. ATM il controllo DataGrid non analizza il suo datacontext alle sue colonne. Questo potrebbe essere risolto in codebehind però stiamo usando il modello MVVM così ho deciso di seguire jamiers approccio

Soluzione:

Inserire il seguente due blocchi di codice in Window.Resources

<Style x:Key="ColumnHeaderStyle" 
      TargetType="{x:Type toolkit:DataGridColumnHeader}"> 
     <Setter Property="ContextMenu" 
       Value="{StaticResource ColumnHeaderContextMenu}" /> 
    </Style> 

    <ContextMenu x:Key="ColumnHeaderContextMenu"> 
     <MenuItem x:Name="MyMenuItem" 
        IsCheckable="True" 
        IsChecked="{Binding DataContext.IsHidden, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type toolkit:DataGrid}}}"/> 
    </ContextMenu> 

Il datagrid cerca quindi qualcosa di simile in XAML

 <toolkit:DataGrid x:Name="MyGrid" 
          AutoGenerateColumns="False" 
          ItemsSource="{Binding SampleCollection, Mode=Default}" 
          EnableColumnVirtualization="True" 
          IsReadOnly="True" 
          ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"> 
      <toolkit:DataGrid.Columns> 
       <toolkit:DataGridTextColumn Binding="{Binding Path=SamplingUser}" 
              Header="{Binding (FrameworkElement.DataContext).IsHidden, RelativeSource={x:Static RelativeSource.Self}}" 
              Visibility="{Binding (FrameworkElement.DataContext).IsHidden, 
               RelativeSource={x:Static RelativeSource.Self}, 
               Converter={StaticResource booleanToVisibilityConverter}}"/> 

Quindi la proprietà visibility su DataGridColumn e la proprietà ischeked sono entrambi database alla proprietà IsHidden sul viewModel.

Nella ViewModel:

public bool IsHidden 
    { 
     get { return isHidden; } 
     set 
     { if (value != isHidden) 
      { 
       isHidden = value; 
       OnPropertyChanged("IsHidden"); 
       OnPropertyChanged("IsVisible"); 
      } 
     } 
    } 

La classe Helper definito da Jaimer:

class DataGridSupport 
{ 
    static DataGridSupport() 
    { 

     DependencyProperty dp = FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn)); 
     FrameworkElement.DataContextProperty.OverrideMetadata (typeof(DataGrid), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnDataContextChanged))); 

    } 

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

istanziare nel ViewModel (solo per mostrare fatto attraverso l'Unità di progetto vero e proprio)

private static DataGridSupport dc = new DataGridSupport(); 

Cheers,

0

Invece di booleanToVisibilityConverter è possibile utilizzare x: static

<Setter TargetName="UIElement" Property="UIElement.Visibility" Value="x:Static Visibility.Hidden" /> 

Statica in XAML: http://msdn.microsoft.com/en-us/library/ms742135.aspx

+0

Votato solo perché l'elettore precedente che ha votato questa risposta non ha fatto non fornire alcuna spiegazione in merito alla motivazione del voto. – Ahmad

6

So che questo è un po 'vecchio. Ma stavo guardando fare questo e questo post è molto più semplice: http://iimaginec.wordpress.com/2011/07/25/binding-wpf-toolkit%E2%80%99s-datagridcolumn-to-a-viewmodel-datacontext-propogation-for-datagrid-columns-the-mvvm-way-to-interact-with-datagridcolumn/

Tutto quello che dovete fare è impostare DataContext sulle colonne e quindi associare visibilità al tuo ViewModel come al solito! :) Semplice ed efficace

+0

Funziona alla grande per me in 3.5 + WPF Toolkit –

+0

+1 Questa è la migliore spiegazione del pattern che ho visto, grazie. – briantyler

12

Ho cercato per un generica, XAML (vale a dire, senza code-behind), automatico e semplice esempio di un menu di scelta rapida di selezione colonne che si lega ad un WPF Intestazione di colonna DataGrid. Ho letto letteralmente centinaia di articoli, ma nessuno di loro sembra fare lo esattamente la cosa giusta, o non sono abbastanza generici. Quindi ecco quello che penso sia la migliore soluzione combinata:

Innanzitutto, inserisci questi nel dizionario delle risorse. Lascerò come esercizio al lettore scrivere il convertitore Visibilità/Booleano per garantire che le caselle di controllo controllino quando la colonna è visibile e viceversa. Si noti che definendo x: Shared = "False" per la risorsa del menu di scelta rapida, otterrà lo stato specifico dell'istanza, il che significa che è possibile utilizzare questo singolo modello/risorsa per tutti i datagrid e che manterranno tutti il ​​proprio stato.

<Converters:VisiblityToInverseBooleanConverter x:Key="VisiblityToInverseBooleanConverter"/> 

<ContextMenu x:Key="ColumnChooserMenu" x:Shared="False" 
      DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}" 
      ItemsSource="{Binding Columns, RelativeSource={RelativeSource AncestorType={x:Type sdk:DataGrid}}}"> 
    <ContextMenu.ItemContainerStyle> 
     <Style TargetType="MenuItem"> 
      <Setter Property="Header" Value="{Binding Header}"/> 
      <Setter Property="AutomationProperties.Name" Value="{Binding Header}"/> 
      <Setter Property="IsCheckable" Value="True" /> 
      <Setter Property="IsChecked" Value="{Binding Visibility, Mode=TwoWay, Converter={StaticResource VisiblityToInverseBooleanConverter}}" /> 
     </Style> 
    </ContextMenu.ItemContainerStyle> 
</ContextMenu> 

<Style x:Key="ColumnHeaderStyle" TargetType="{x:Type Primitives:DataGridColumnHeader}"> 
    <Setter Property="ContextMenu" Value="{StaticResource ColumnChooserMenu}" /> 
</Style> 

<ContextMenu x:Key="GridItemsContextMenu" > 
    <MenuItem Header="Launch Do Some other action"/> 
</ContextMenu> 

Poi definire il DataGrid come segue (dove OrdersQuery è qualche fonte dei dati esposti dalla View-modello):

<sdk:DataGrid ItemsSource="{Binding OrdersQuery}" 
       AutoGenerateColumns="True" 
       ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}" 
       ContextMenu="{StaticResource GridItemsContextMenu}"> 

    <!-- rest of datagrid stuff goes here --> 

</sdk:DataGrid> 

Questo vi darà la seguente:

  1. Un contesto menu associato alle intestazioni di colonna che funge da selettore di colonna.
  2. Un menu di scelta rapida associato agli elementi nella griglia (per eseguire azioni sugli oggetti stessi - di nuovo, il binding delle azioni è un esercizio per il lettore).

Spero che questo aiuti le persone che hanno cercato un esempio come questo.

+2

Questa risposta dovrebbe essere più alta. Soluzione semplice ed elegante –

+1

Soluzione molto pulita! Comunque una nota: funziona solo se le colonne sono generate automaticamente. Ovviamente, ovviamente, ma vale la pena menzionarlo. –

+0

Sei sicuro? Piuttosto sicuro che funzioni per colonne generate automaticamente o generate esplicitamente (ma non l'ho provato per un paio d'anni quindi potrebbe essere sbagliato). – Webreaper

Problemi correlati