Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM Grouping Items in ListView

I cannot understand what I'm doing wrong. I want to group items in listView. In result I want to see something like that:

enter image description here

It'm using MVVM pattern. It's my XAML code.

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

It's my 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
}
  • Why can not I bind "FirstName" property with Expander.Header TextBlock?
  • Why have I object type
    MS.Internal.Data.CollectionViewGroupInternal inside Expander.Header(if i wrote inside Expander.Header Text="{Binding}")>?

How should I change my XAML or .CS code to produce these results?

like image 958
Leonid Avatar asked Nov 21 '10 09:11

Leonid


1 Answers

I found answer on this question by myself.

The object that is sent into the converter is of the type: MS.Internal.Data.CollectionViewGroupInternal.

The main reason is to use "Name" for databinding the group names is simply because that is the property in CollectionViewGroupInternal that contains the name that the current "group collection" has (according to the GroupDescription that you specified).

Not important What was GropertyName in PropertyGroupDescription. You have to always use {Binding Path=Name} in GroupStyle container.

I had to change only one string in my XAML.

From:

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

To:

<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"/>
like image 159
Leonid Avatar answered Oct 20 '22 04:10

Leonid