2010-11-21 17 views
14

No puedo entender lo que estoy haciendo mal. Quiero agrupar elementos en listView. En consecuencia quiero ver algo así:MVVM Agrupación de elementos en ListView

enter image description here

It'm con el patrón MVVM. Es mi código 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> 

Es mi 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 
} 
  • Por qué no puedo obligar a "Nombre" propiedad con Expander.Header TextBlock?
  • ¿Por qué he objeto de tipo
    MS.Internal.Data.CollectionViewGroupInternal dentro Expander.Header (si escribía el interior Expander.Header Text = "{Binding}")>?

¿Cómo debo cambiar mi XAML o código .CS para producir these results?

Respuesta

20

Encontré la respuesta a esta pregunta por mi cuenta.

El objeto que se envía al convertidor es del tipo: MS.Internal.Data.CollectionViewGroupInternal.

La razón principal es usar "Nombre" para enlazar los nombres de grupo simplemente porque esa es la propiedad en CollectionViewGroupInternal que contiene el nombre que tiene la "colección de grupo" actual (de acuerdo con la Descripción de grupo que especificó).

No importante Qué era GropertyName en PropertyGroupDescription. Tiene que siempre use {Binding Path = Name} en el contenedor GroupStyle.

Tuve que cambiar solo una cadena en mi XAML.

Desde:

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

Para:

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

Me pregunto cómo hacer esto con múltiples PropertyGroupDescriptions ... – Sven

+1

Esto es extremadamente bazar. Lo he notado aquí en esta publicación http://www.wpf-tutorial.com/listview-control/listview-grouping/ y pensé que esto podría ser un error tipográfico. ¿Por qué debería ser siempre "Nombre" pero no el nombre del enlace real? Salud. – Mehrad

+1

"Nombre" es el nombre de la propiedad que contiene el elemento que ha agrupado. Tiene un grupo de elementos que comparten un Nombre y la propiedad "Nombre" tiene ese valor común. Esto se vuelve más obvio cuando agrupa en un tipo complejo. –

Cuestiones relacionadas