2010-11-21 15 views
14

Non riesco a capire cosa sto facendo male. Voglio raggruppare elementi in listView. Nel risultato che voglio vedere qualcosa di simile:MVVM Raggruppamento articoli in ListView

enter image description here

It'm utilizzando modello MVVM. È il mio codice XAML.

<CollectionViewSource x:Key="EmploeeGroup"        
         Source="{Binding Path=AllEmploees}"> 
    <CollectionViewSource.GroupDescriptions> 
    <PropertyGroupDescription PropertyName="FirstName" /> 
    </CollectionViewSource.GroupDescriptions> 
</CollectionViewSource> 

<ListView AlternationCount="2" 
      DataContext="{StaticResource EmploeeGroup}" 
      ItemsSource="{Binding IsAsync=True}" Padding="0,0,0,10"> 
    <ListView.GroupStyle> 
    <GroupStyle> 
     <GroupStyle.ContainerStyle> 
     <Style TargetType="{x:Type GroupItem}"> 
      <Setter Property="Margin" Value="0,0,0,5"/> 
      <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type GroupItem}"> 
       <Expander IsExpanded="True" BorderBrush="#FFA4B97F" 
              BorderThickness="0,0,0,1"> 
        <Expander.Header> 
        <DockPanel> 
         <TextBlock FontWeight="Bold" 
           Text="Name: "/> 
         <TextBlock FontWeight="Bold" 
           Text="{Binding Path=FirstName}"/> 
        </DockPanel> 
        </Expander.Header> 
        <Expander.Content> 
        <ItemsPresenter /> 
        </Expander.Content> 
       </Expander> 
       </ControlTemplate> 
      </Setter.Value> 
      </Setter> 
     </Style> 
     </GroupStyle.ContainerStyle> 
    </GroupStyle> 
    </ListView.GroupStyle> 
    <ListView.View> 
    <GridView> 
     <GridViewColumn Width="150" 
         Header="FirstName" 
         DisplayMemberBinding="{Binding Path=FirstName}"/> 
     <GridViewColumn Width="150" 
         Header="LastName" 
         DisplayMemberBinding="{Binding Path=LastName}"/> 
    </GridView> 
    </ListView.View> 
</ListView> 

E 'il mio EmploeeListViewModel.cs

public class EmploeeListViewModel: ViewModelBase 
{ 
    readonly EmploeeRepository _emploeeRepository; 

    private ObservableCollection<EmploeeViewModel> _allmpl; 
    public ObservableCollection<EmploeeViewModel> AllEmploees 
    { 
    get 
    { 
     if (_allmpl == null) 
     { 
     _allmpl = new ObservableCollection<EmploeeViewModel>(); 
     CreateAllEmploee(); 
     } 
     return _allmpl; 
    } 
    } 

    public EmploeeListViewModel(EmploeeRepository emploeeRepository) 
    { 
    if (emploeeRepository == null) 
     throw new ArgumentNullException("emploeeRepository"); 

    _emploeeRepository = emploeeRepository; 
    _emploeeRepository.EmploeeAdded += this.OnEmploeeAddedToRepository; 
    } 

private void CreateAllEmploee() 
{ 
    List<EmploeeViewModel> all = 
       (from emploee in _emploeeRepository.GetEmploees() 
       select new EmploeeViewModel(emploee)).ToList(); 
    foreach (EmploeeViewModel evm in all) 
    { 
    evm.PropertyChanged += this.OnEmploeeViewModelPropertyChanged; 
    AllEmploees.Add(evm); 
    } 
    this.AllEmploees.CollectionChanged += this.OnCollectionChanged; 
} 

//this.OnCollectionChanged; 
//this.OnEmploeeViewModelPropertyChanged; 
} 

EmploeeViewModel.cs

public class EmploeeViewModel : ViewModelBase 
{ 
    #region Fields 
    Emploee _emploee; 
    bool _isSelected; 
    #endregion 

    #region Constructor 
    public EmploeeViewModel(Emploee emploee) 
    { 
     if (emploee == null) 
     throw new ArgumentNullException("emploee"); 
     this._emploee = emploee; 
    } 
    #endregion 

    #region Emploee Properties 
    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set 
     { 
     if (value == _isSelected) 
      return; 

     _isSelected = value; 
     base.OnPropertyChanged("IsSelected"); 
     } 
    } 

    public string FirstName 
    { 
     get { return _emploee.FirstName; } 
     set 
     { 
     if (value == _emploee.FirstName) 
      return; 
     _emploee.FirstName = value; 
     base.OnPropertyChanged("FirstName"); 
     } 
    } 

    public string LastName 
    { 
     get { return _emploee.LastName; } 
     set 
     { 
     if (value == _emploee.LastName) 
      return; 
     _emploee.LastName = value; 
     base.OnPropertyChanged("LastName"); 
     } 
    } 
    #endregion 
} 
  • Perché non posso legare "FirstName" proprietà con Expander.Header TextBlock?
  • Perché sono oggetto di tipo
    MS.Internal.Data.CollectionViewGroupInternal all'interno Expander.Header (se ho scritto all'interno Expander.Header Text = "{Binding}")>?

Come dovrei cambiare il mio XAML o il codice .CS per produrre these results?

risposta

20

Ho trovato risposta a questa domanda da solo.

L'oggetto che viene inviato al convertitore è del tipo: MS.Internal.Data.CollectionViewGroupInternal.

Il motivo principale è utilizzare "Nome" per l'associazione dati dei nomi di gruppo semplicemente perché questa è la proprietà in CollectionViewGroupInternal che contiene il nome che ha la "raccolta di gruppi" corrente (in base al GroupDescription specificato).

Non importante Che cos'era GropertyName in PropertyGroupDescription. È necessario sempre utilizzare {Percorso obbligatorio = Nome} nel contenitore GroupStyle.

Ho dovuto modificare solo una stringa nel mio XAML.

Da:

<TextBlock FontWeight="Bold" Text="{Binding Path=FirstName}"/> 

A:

<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/> 
+0

mi chiedo come fare questo con più PropertyGroupDescriptions ... – Sven

+1

Ciò è estremamente bazar. L'ho notato qui in questo post http://www.wpf-tutorial.com/listview-control/listview-grouping/ e ho pensato che questo potrebbe essere un refuso. Perché mai dovrebbe essere sempre "Nome" ma non il nome dell'attuale associazione !!! Acclamazione amico. – Mehrad

+1

"Nome" è il nome della proprietà che contiene l'elemento su cui è stato effettuato il raggruppamento. Hai un gruppo di elementi che condividono tutti un FirstName e la proprietà "Name" contiene quel valore comune. Questo diventa più evidente quando si raggruppa su un tipo complesso. –