2014-06-10 31 views
6

Używam C# i WPF i mam ListView, który przechowuje elementy z CheckBox w pierwszej kolumnie. Źródło ItemsSource ListView jest ustawione w kodzie (nie poprzez wiązanie) i zawiera wystąpienia klasy "Element" z właściwościami "Nazwa", "Typ" i "Wybrane".ListView z zgrupowanymi elementami - zaznacz wszystkich członków grupy za pomocą pola wyboru nagłówka grupy

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

ListView widoku jest ustawiony na GridView z pierwszej kolumnie pole wyboru, który jest zobowiązany do wybranej właściwości - np pole wyboru Znaczną ich „wybrany”.

Dodaję grupowanie do tego ListView (pogrupowane według "Typ"), a GroupStyle zawiera również CheckBox.

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

XAML dla ListView zawiera GridView i 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> 

końcu na moje pytanie: co chciałbym się zdarzyć, aby móc skorzystać z wyboru w grupie nagłówek, aby wybrać wszystkie lub żadne z elementów w danej grupie. Na przykład:

Example

Kliknięcie nagłówka wyboru grupy należy zaznaczyć wszystkie pozycje w danej grupie, jeżeli nie są one jeszcze wybrany. Ponowne kliknięcie powinno usunąć zaznaczenie (odznacz) wszystkich elementów w tej grupie. Jeśli użytkownik ręcznie zaznaczy lub odznaczy niektóre elementy w grupie, byłoby miło, gdyby pole wyboru nagłówka grupy pokazywało nieokreślony stan, ale po prostu niezaznaczone byłoby również dobre.

Nie mam pojęcia, od czego zacząć. Zakładam, że będę musiał powiązać właściwość IsChecked pola wyboru nagłówka grupy, ale nie wiem, do czego go przypisać, ponieważ datacontext będzie czymś w rodzaju GroupDescriptor, który nie zawiera żadnych informacji o grupie, ani jakie pozycje znajdują się w tej grupie (prawda?).

Nie przestrzegam ściśle MVVM, więc nie martwię się o to, że zrobię to wszystko w wiązaniach iw moim modelu widokowym, byłoby w porządku z czymś w rodzaju słuchania zdarzenia Checked zaznaczonego pola wyboru i jakoś zorientować się w kodzie, które elementy należy sprawdzić. Na przykład; gdybym mógł posłuchać zdarzenia Checked i jakoś wyodrębnić Typ grupy, byłbym w większości ustawiony (mógłbym przejrzeć całą listę i wybrać wszystkie osoby z pasującą grupą). Ale nie widzę nawet sposobu na zrobienie tego; Mogę uzyskać CheckBox w zdarzeniu Checked (nadawcy) i mogę zapętlić się z wszystkimi kontrolkami nadrzędnymi, ale nigdzie nie widzę sposobu na wyodrębnienie informacji o właściwości, którą zgrupowuję ...

Dowolna pomoc byłaby świetna!

Odpowiedz

0

Można obsłużyć, gdy nagłówek grupy jest zaznaczony, a następnie przeglądać elementy w grupie i ustawić IsChecked na true.

+0

Ale jak mogę uzyskać elementy w grupie? Musiałbym znać wartość nieruchomości, którą zgrupowałem, lub zdobyć elementy grupy w jakiś inny sposób i nie mogę znaleźć żadnego sposobu, aby je zdobyć. –

2

Wyjaśniałem, wszystko, czego potrzebowałem, to DataContext CheckBox. To nie jest najstarsze rozwiązanie (na pewno nie MVVM), ale wygląda na to, że działa dobrze.

Po prostu dodaj zaznaczone i niezaznaczone funkcje obsługi zdarzeń do pola wyboru w stylu grupy, przesuń DataContext do grupy CollectionViewGroup, która zawiera elementy.

W przypadku zagnieżdżone grupowanie przedmioty kolekcja zawiera inną instancję CollectionViewGroup, więc trzeba rekurencyjnie pętli tych pozycji podczas znaleźć inny (zagnieżdżony) Grupa:

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

Teraz jeszcze trzeba wymyślić jak reagować na sprawdzanie elementów i zmieniając pole wyboru w odpowiedniej grupie.

+0

znalazłeś rozwiązanie dla tego? – SZT