2014-06-10 12 views
6

Sto usando C# e WPF e ho una ListView che contiene voci con un CheckBox nella prima colonna. ItemsSource di ListView è impostato in codice (non tramite binding) e contiene istanze di una classe 'Item' con proprietà 'Name', 'Type' e 'Selected'.ListView con elementi raggruppati - selezionare tutti i membri del gruppo tramite gruppo di testa casella

public class Item : INotifyPropertyChanged 
{ 
    private string _name; 
    private bool _selected; 
    private string _type; 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      _name = value; 
      this.OnPropertyChanged(); 
     } 
    } 

    public bool Selected 
    { 
     get { return _selected; } 
     set 
     { 
      _selected = value; 
      this.OnPropertyChanged(); 
     } 
    } 

    public string Type 
    { 
     get { return _type; } 
     set 
     { 
      _type = value; 
      this.OnPropertyChanged(); 
     } 
    } 

    protected virtual void OnPropertyChanged([CallerMemberName] string property = "") 
    { 
     if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(property)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

L'opinione del ListView è impostato su una GridView con la prima colonna di una casella di controllo che è legato alla proprietà Selected - ad esempio la casella di controllo significa essere 'selezionato'.

sto aggiungendo raggruppamento a questo ListView (diviso per 'Tipo'), e il GroupStyle contiene una CheckBox pure.

 var lst = new List<Item>(); 
     lst.Add(new Item { Name = "A", Type = "1" }); 
     lst.Add(new Item { Name = "B", Type = "1" }); 
     lst.Add(new Item { Name = "C", Type = "1" }); 
     lst.Add(new Item { Name = "A", Type = "2" }); 
     lst.Add(new Item { Name = "B", Type = "2" }); 
     lst.Add(new Item { Name = "C", Type = "2" }); 

     listview.ItemsSource = lst; 

     var view = CollectionViewSource.GetDefaultView(lst); 
     view.GroupDescriptions.Add(new PropertyGroupDescription("Type")); 

Il XAML per il ListView contiene il GridView e il GroupStyle:

<ListView x:Name="listview"> 

     <!-- View --> 
     <ListView.View> 
      <GridView> 
       <GridViewColumn Width="50"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate DataType="cls:Item"> 
          <CheckBox IsChecked="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 

       <GridViewColumn Width="300" Header="Name" DisplayMemberBinding="{Binding Name, UpdateSourceTrigger=PropertyChanged}"></GridViewColumn> 

       <GridViewColumn Width="100" Header="Type" DisplayMemberBinding="{Binding Type}"></GridViewColumn> 
      </GridView> 
     </ListView.View> 

     <!-- Group style --> 
     <ListView.GroupStyle> 
      <GroupStyle> 
       <GroupStyle.ContainerStyle> 
        <Style TargetType="{x:Type GroupItem}"> 
         <Setter Property="Template"> 
          <Setter.Value> 
           <ControlTemplate> 
            <Expander IsExpanded="True"> 
             <Expander.Header> 
              <StackPanel Orientation="Horizontal"> 
               <CheckBox></CheckBox> 
               <TextBlock Text="{Binding Name}" /> 
               <TextBlock Text="{Binding ItemCount, StringFormat='- {0} item(s)'}" /> 
              </StackPanel> 
             </Expander.Header> 
             <ItemsPresenter /> 
            </Expander> 
           </ControlTemplate> 
          </Setter.Value> 
         </Setter> 
        </Style> 
       </GroupStyle.ContainerStyle> 
      </GroupStyle> 
     </ListView.GroupStyle> 
    </ListView> 

Finalmente alla mia domanda: che cosa vorrei che accada è quello di essere in grado di utilizzare la casella di controllo del gruppo intestazione per selezionare tutti o nessuno degli elementi in quel particolare gruppo. Ad esempio:

Example

Marcando la casella intestazione gruppo dovrebbe selezionare tutti gli elementi in quel particolare gruppo se non sono ancora selezionati. Facendo nuovamente clic, devi deselezionare (deseleziona) tutti gli elementi di quel gruppo. Se l'utente seleziona o deseleziona manualmente alcuni elementi in un gruppo, sarebbe bello che la casella di controllo dell'intestazione di gruppo mostri uno stato indeterminato, ma che sia deselezionata sarebbe anche utile.

ho idea da dove cominciare con questo. Presumo che avrò bisogno di associare la proprietà IsChecked della casella di controllo dell'intestazione di gruppo, ma non so a cosa collegarlo perché il datacontext sarà una specie di cosa GroupDescriptor che non contiene alcuna informazione sul gruppo, né quali oggetti sono in quel gruppo (giusto ??).

Non sto seguendo rigorosamente MVVM quindi non mi preoccupo di fare tutto in binding e nel mio viewmodel, mi andrebbe bene con qualcosa come ascoltare l'evento Checked della checkbox e in qualche modo capire in codice quali elementi dovrebbe essere controllato Per esempio; se potessi ascoltare l'evento controllato e in qualche modo estrarre il tipo del gruppo, sarei per lo più impostato (potrei passare attraverso l'intera lista e selezionare tutti quelli con il gruppo corrispondente). Ma non vedo nemmeno un modo per farlo; Posso ottenere il CheckBox nell'evento Checked (il mittente) e posso eseguire il loop su tutti i controlli genitore ma da nessuna parte vedo un modo per estrarre informazioni sulla proprietà che sto raggruppando ...

Qualsiasi l'aiuto sarebbe fantastico!

risposta

0

È in grado di gestire quando l'intestazione di gruppo viene controllato e quindi un ciclo tra gli articoli di questa categoria e set IsChecked su true.

+0

Ma come ottengo gli articoli nel gruppo? Dovrei conoscere il valore della proprietà su cui sto raggruppando o ottenere gli elementi del gruppo in un altro modo e non riesco a trovare alcun modo per ottenerli. –

2

ho capito, tutto quello che serviva era il DataContext del CheckBox. Non è la soluzione più pessima (non MVVM di sicuro) ma sembra funzionare bene.

Basta aggiungere gestori di eventi controllati e deselezionata per la casella di controllo nello stile del gruppo, il cast del DataContext ad un CollectionViewGroup, che contiene gli elementi.

In caso di nidificato raggruppamento dei prodotti che raccolta contiene un'altra istanza di CollectionViewGroup, quindi è necessario in modo ricorsivo ciclo tra gli elementi quando si trova un'altra (nested) Gruppo:

private void OnGroupChecked(object sender, RoutedEventArgs e) 
    { 
     this.HandleGroupCheck((CheckBox)sender, true); 
    } 

    private void OnGroupUnchecked(object sender, RoutedEventArgs e) 
    { 
     this.HandleGroupCheck((CheckBox)sender, false); 
    } 

    private void HandleGroupCheck(CheckBox sender, bool check) 
    { 
     var group = (CollectionViewGroup) sender.DataContext; 
     this.HandleGroupCheckRecursive(group, check); 
    } 

    private void HandleGroupCheckRecursive(CollectionViewGroup group, bool check) 
    { 
     foreach (var itemOrGroup in group.Items) 
     { 
      if (itemOrGroup is CollectionViewGroup) 
      { 
       // Found a nested group - recursively run this method again 
       this.HandleGroupCheckRecursive(itemOrGroup as CollectionViewGroup, check); 
      } 
      else if (itemOrGroup is Item) 
      { 
       var item = (Item)itemOrGroup; 
       item.Selected = check; 
      } 
     } 
    } 

Ora ho ancora bisogno di capire come rispondere al controllo degli articoli e cambiare la casella di controllo nel gruppo corrispondente.

+0

hai trovato una soluzione per questo? – SZT

Problemi correlati