3

I have created a listview control in WPF and has success fully bound Icollectionview object of ObservableCollection<object>. My listview columns are created dynamically. I have to sort and group my listview and it is not working properly. My code is as below.

private void LaodList()
{
    dt = new DataTable();
    dt.Columns.Add("AA", typeof(string));
    dt.Columns.Add("BB", typeof(string));
    dt.Columns.Add("cc", typeof(string));
    dt.Rows.Add("12", "66",11);
    dt.Rows.Add("33", "44",22);
    dt.AcceptChanges();


    GridView gv = new GridView();
    //gv.AllowsColumnReorder = true;

    List<string> myItemsCollection = new List<string>();
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        GridViewColumn col = new GridViewColumn();
        col.Header = dt.Columns[i].ColumnName;
        col.DisplayMemberBinding = new Binding(string.Format("[{0}]", i));
        gv.Columns.Add(col);
        myItemsCollection.Add(col.Header.ToString());
    }

    LvItems.View = gv;
    this.Source = CollectionViewSource.GetDefaultView(LoadItems(dt)) ;  
    LvItems.DataContext = this.Source;
    cmbGroups.ItemsSource = myItemsCollection;
}


public ObservableCollection<object> LoadItems(DataTable dt)
{
    ObservableCollection<object> items = new ObservableCollection<object>();
    foreach (DataRow dataRow in dt.Rows)
    {
         items.Add(dataRow.ItemArray);
    }

    return items;
 }

//sort////////////////////////

private void ListView_Click(object sender, RoutedEventArgs e)
{

    GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;
    if (currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding)
    {
        if (this.Source.SortDescriptions.Count((item) => item.PropertyName.Equals(currentHeader.Column.Header.ToString())) > 0)
        {
            SortDescription currentPropertySort = this.Source
                        .SortDescriptions
                        .First<SortDescription>(item => item.PropertyName.Equals(currentHeader.Column.Header.ToString()));

                    //Toggle sort direction.
                    ListSortDirection direction =
                        (currentPropertySort.Direction == ListSortDirection.Ascending) ?
                        ListSortDirection.Descending : ListSortDirection.Ascending;

                    //Remove existing sort
                    this.Source.SortDescriptions.Remove(currentPropertySort);
                    this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), direction));
                }
                else
                {
                    this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));
                }

                this.Source.Refresh();
            }

        }

//group////////////////////

private void btnGroup_Click(object sender, RoutedEventArgs e)
{
            this.Source.GroupDescriptions.Clear();

            PropertyInfo pinfo = typeof(object).GetProperty(cmbGroups.Text);
            if (pinfo != null)
                this.Source.GroupDescriptions.Add(new PropertyGroupDescription(pinfo.Name));

}

WPF code is as below

<ListView ItemsSource="{Binding}" x:Name="LvItems" ButtonBase.Click="ListView_Click" IsSynchronizedWithCurrentItem="True" Grid.Row="1" Margin="0,22,0,43">
        <ListView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock FontSize="15" FontWeight="Bold" Text="{Binding}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </ListView.GroupStyle>

    </ListView>
Dinu
  • 123
  • 1
  • 2
  • 7

1 Answers1

6

Since you are using WPF you shall use DataBindings. Expose your ICollectionView as a property and bind on it

public ICollectionView MyList
{
    get
    {
        if(_mylist == null)
            _mylist = CollectionViewSource.GetDefaultView(observableCollection);
        return _mylist;
    }
}

In the XAML you apply the binding as follows

<ListView ItemsSource="{Binding Path=MyList}"/>

And now you apply the sorting on that property

MyList.SortDescriptions.Remove(...);
MyList.SortDescriptions.Add(...);

MyList.GroupDescription.Add(...);

This has the drawback that every Remove or Add on a SortDescription or GroupDescription will refresh the ListView. Normally this is unwanted if you want to apply many sortings in one step. Then you should enclose the block with following:

using(MyList.DeferRefresh())
{
    //put your changes in sorting and grouping here
}
Michael Mairegger
  • 6,833
  • 28
  • 41
  • I think the problem is with binding property set in grouping. As I am adding data and columns at runtime how can I set binding of grouping also at runtime. Please advice. – Dinu Nov 13 '13 at 07:07
  • You can also do this in the codebehind, either with the event of the listview or with commands. BTW, if you use a DataGrid you do not have the need to implement the sort, because the DataGrid control already allows sorting. – Michael Mairegger Nov 13 '13 at 07:22
  • how about grouping ? can you give me an example? – Dinu Nov 13 '13 at 07:38
  • You will find a complete HowTo here: [Group, Sort in DataGrid](http://msdn.microsoft.com/en-us/library/ff407126(v=vs.110).aspx) – Michael Mairegger Nov 13 '13 at 08:16