views:

115

answers:

1

As we can see in Photoshop layer window (or other image editting tool also),

it has several features:

  1. groups with folder-like header (collapse/expandable)
  2. ungroupped item (no header)
  3. sort "manually" by dragging.

In case of No 1, I made groupped item with expander control. (ref)

In case of No 3, Sort manually can be solved with this code. (ref)

but I don't know how to list ungroupped items together. Of course, the ungroupped items may not have a header.

I am using ICollectionView and MVVM.

Does ICollectionView can make it?

A: 

ICollectionView cannot. GroupStyle.ContainerStyleSelector can. Here is an example.

XAML:

<Window x:Class="WpfWindowDrag.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WpfWindowDrag="clr-namespace:WpfWindowDrag"
        Title="Window1" Height="300" Width="300">
  <Window.Resources>
    <!--Container style for a groupped item-->
    <Style x:Key="RegularContainerStyle" TargetType="{x:Type GroupItem}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate>
            <Expander Header="{Binding Name}" IsExpanded="True">
              <ItemsPresenter />
            </Expander>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <!--Container style for root objects (i.e. non grouped)-->
    <Style x:Key="RootContainerStyle" TargetType="{x:Type GroupItem}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate>
            <ItemsPresenter />
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <!--This guy lets us select choose proper group for an item.-->
    <WpfWindowDrag:CountryStyleSelector x:Key="ContainerStyleSelector"
                                        RegularGroupStyle="{StaticResource RegularContainerStyle}"
                                        RootGroup="{StaticResource RootContainerStyle}" />
  </Window.Resources>
  <Grid>
    <ListView x:Name="lv">
      <ListView.GroupStyle>
        <GroupStyle ContainerStyleSelector="{StaticResource ContainerStyleSelector}" />
      </ListView.GroupStyle>
      <ListView.View>
        <GridView>
          <GridViewColumn DisplayMemberBinding="{Binding Path=Name}" Header="Name" />
        </GridView>
      </ListView.View>
    </ListView>
  </Grid>
</Window>

CS:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfWindow
{
  public partial class Window1 : Window
  {
    private const int NumberOfRecords = 20;
    private readonly ObservableCollection<Person> _myList;

    public Window1()
    {
      InitializeComponent();

      var countries = new[] { "", "US", "China", "India", "Japan", "Ukraine" };

      var countriesCount = countries.Length;
      _myList = new ObservableCollection<Person>();
      var rnd = new Random();

      for (int i = 0; i < NumberOfRecords; i++)
      {
        int countryIndex = rnd.Next(countriesCount);
        _myList.Add(new Person() { Name = string.Format("Name {0}", i), Country = countries[countryIndex] });
      }

      ICollectionView view = CollectionViewSource.GetDefaultView(_myList);
      view.GroupDescriptions.Add(new PropertyGroupDescription("Country"));
      view.SortDescriptions.Add(new SortDescription("Country", ListSortDirection.Ascending));
      view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

      lv.ItemsSource = view;
    }
  }

  public class Person
  {
    public string Name { get; set; }
    public string Country { get; set; }
  }

  public class CountryStyleSelector : StyleSelector
  {
    public Style RegularGroupStyle { get; set; }

    public Style RootGroup { get; set; }

    public override Style SelectStyle(object item, DependencyObject container)
    {
      var cvg = item as CollectionViewGroup;
      if (cvg == null)
      {
        return base.SelectStyle(item, container);
      }
      return string.IsNullOrEmpty(cvg.Name as string) ? RootGroup : RegularGroupStyle;
    }
  }
}

Keep in mind though, having items group automatically disables virtualization and impacts performance. If you need something really fast with thousands of items inside you'd probably write your own control or look for 3rd parties.

Cheers, Anvaka.

Anvaka
Anvaka, thanks for your help. I successfully display groupped and ungroupped items with your code. But, my problem is, the groupped item are always positioned at the bottom. In my thought, group itself doesn't have any sort description in order to position between ungroupped items. But how can I mix(sort) ungroupped and groupped items in a listView?
Youngjae
Youngjae, you can use two SortDescriptions as described here: http://bea.stollnitz.com/blog/?p=17
Anvaka
Thans in advance. I think it will be needed whole fresh appoach. I will try to solve my problem using naive stackpanel.
Youngjae
You are welcome :)! Cheers
Anvaka