使用ICollectionView对ObservableCollection进行排序不能正常工作

时间:2015-01-29 13:00:10

标签: c# wpf observablecollection collectionviewsource icollectionview

要生成错误,请选择TopDataGrid中的任何项目。因此,项目集合将加载到BottomDataGrid。这个集合按我指定的Name属性排序!然后选择TopDataGrid中的任何其他项目。结果是ItemsSource的{​​{1}}将被重新加载。现在收藏品没有分类!该集合看起来像我在代码中指定的那样。此外,如果我使用调试器检查BottomDataGrid,我会看到已排序的集合。

我知道我可以_customerView使用ListOrderBy来明确命令用户界面更新自己,而不是INotifyPropertyChangedObservableCollection。但我认为这不是正确的方法。

赢7,.Net 4.0。只需复制并粘贴。

ICollectionView

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <DataGrid Grid.Row="0" 
                AutoGenerateColumns="False"
                ItemsSource="{Binding Items}"
                SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                CanUserAddRows="False"
                CanUserDeleteRows="False"
                CanUserResizeRows="False"
                CanUserSortColumns="False"
                SelectionMode="Single"
                SelectionUnit="FullRow">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Name}"></DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
    <DataGrid Grid.Row="1" 
                AutoGenerateColumns="False"
                ItemsSource="{Binding SelectedItem.MyCollectionView}"
                CanUserAddRows="False"
                CanUserDeleteRows="False"
                CanUserResizeRows="False"
                CanUserSortColumns="False"
                SelectionMode="Single"
                SelectionUnit="FullRow">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Name}"></DataGridTextColumn>
            <DataGridTextColumn Binding="{Binding Index}"></DataGridTextColumn>
        </DataGrid.Columns>

    </DataGrid>

    <Grid Grid.Row="2">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="0" 
                    Text="{Binding Name1}"></TextBox>
        <TextBox Grid.Column="1" 
                    Text="{Binding Index}"></TextBox>
    </Grid>
</Grid>

更新

public class TopGridItem
{
    private ObservableCollection<BottomGridItem> _collection;
    public ObservableCollection<BottomGridItem> Collection
    {
        get { return _collection; }
    }

    public String Name { get; set; }

    public ICollectionView MyCollectionView
    {
        get
        {
            ICollectionView _customerView = CollectionViewSource.GetDefaultView(Collection);
            _customerView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

            return _customerView;
        }
    }

    public TopGridItem()
    {
        _collection = new ObservableCollection<BottomGridItem>();
        _collection.Add(new BottomGridItem { Name = "bbbbbb" });
        _collection.Add(new BottomGridItem { Name = "aaaaa" });
        _collection.Add(new BottomGridItem { Name = "aaaaa" });
        _collection.Add(new BottomGridItem { Name = "ccccc" });
        _collection.Add(new BottomGridItem { Name = "dddddd" });
    }

}

public class BottomGridItem
{
    public String Name { get; set; }
    public String Index { get; set; }
}

/// <summary>
/// Логика взаимодействия для NewWindow.xaml
/// </summary>
public partial class ProgressWindow : INotifyPropertyChanged
{
    public TopGridItem _selectedItem;

    public String Name1 { get; set; }
    public String Index { get; set; }
    public ObservableCollection<TopGridItem> Items { get; set; }

    public TopGridItem SelectedItem 
    {
        get { return _selectedItem; }

        set
        {
            _selectedItem = value;
            OnPropertyChanged("SelectedItem");

        }
    }

    public ProgressWindow()
    {
        InitializeComponent();
        DataContext = this;

        Items = new ObservableCollection<TopGridItem>();
        Items.Add(new TopGridItem {Name = "One"});
        Items.Add(new TopGridItem {Name = "Two"});
        Items.Add(new TopGridItem {Name = "Three"});
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

似乎在private void ClearSortDescriptionsOnItemsSourceChange() { this.Items.SortDescriptions.Clear(); this._sortingStarted = false; List<int> descriptionIndices = this.GroupingSortDescriptionIndices; if (descriptionIndices != null) descriptionIndices.Clear(); foreach (DataGridColumn dataGridColumn in (Collection<DataGridColumn>) this.Columns) dataGridColumn.SortDirection = new ListSortDirection?(); } private static object OnCoerceItemsSourceProperty(DependencyObject d, object baseValue) { DataGrid dataGrid = (DataGrid) d; if (baseValue != dataGrid._cachedItemsSource && dataGrid._cachedItemsSource != null) dataGrid.ClearSortDescriptionsOnItemsSourceChange(); return baseValue; } 方法中排序已清除,不再重新指定。我想这就是问题所在。

2 个答案:

答案 0 :(得分:1)

经过一些调查和尝试后,我想我可以建议至少两种解决方案。

首先:

public TopGridItem SelectedItem 
{
    get { return _selectedItem; }

    set
    {
        _selectedItem = value;
        OnPropertyChanged("SelectedItem");

        // _dataGrid - link to BottomDataGrid  
        _dataGrid.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

    }
}

第二

public TopGridItem SelectedItem 
{
    get { return _selectedItem; }

    set
    {
        _selectedItem = value;
        OnPropertyChanged("SelectedItem");

        if (_selectedItem != null)
        _selectedItem.MyCollectionView.Refresh();
    }
}

答案 1 :(得分:0)

有一个hacky解决方法:O)

更改您的TopGridItem类,使其实现INotifyPropertyChanged,然后更改MyCollectionView属性,如下所示:

public ICollectionView MyCollectionView
{
    get
    {
        return _myCollectionView;
    }
    set
    {
        _myCollectionView = value;
        OnPropertyChanged("MyCollectionView");
    }
}
ICollectionView _myCollectionView;

将公共方法添加到TopGridItem,如下所示:

public void ResetView()
{
    MyCollectionView = null;  // This is the key to making it work
    ICollectionView customerView = CollectionViewSource.GetDefaultView(_collection);
    customerView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
    MyCollectionView = customerView;
}

这要求_collection成为类字段而不是仅在构造函数中使用的变量。说到:

public TopGridItem()
{
    _collection = new ObservableCollection<BottomGridItem>();
    _collection.Add(new BottomGridItem { Name = "bbbbbb" });
    _collection.Add(new BottomGridItem { Name = "aaaaa" });
    _collection.Add(new BottomGridItem { Name = "aaaaa" });
    _collection.Add(new BottomGridItem { Name = "ccccc" });
    _collection.Add(new BottomGridItem { Name = "dddddd" });

    ResetView();
}

请注意对ResetView的调用。

现在,您需要在SelectedItem ProgressWindow属性设置器中执行的操作是在选择更改时调用ResetView方法:

public TopGridItem SelectedItem 
{
    get { return _selectedItem; }

    set
    {
        _selectedItem = value;
        OnPropertyChanged("SelectedItem");

        if (_selectedItem != null)
        {
            _selectedItem.ResetView();
        }
    }
}

我在这里测试了它,它似乎工作。如果没有,那么我必须在某个地方打错或者可能会错过我发布的代码中的内容。


代码的工作版本

<强> XAML:

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <DataGrid Grid.Row="0"
                  AutoGenerateColumns="False"
                  ItemsSource="{Binding Items}"
                  SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                  CanUserAddRows="False"
                  CanUserDeleteRows="False"
                  CanUserResizeRows="False"
                  CanUserSortColumns="False"
                  SelectionMode="Single"
                  SelectionUnit="FullRow">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

        <DataGrid Grid.Row="1"
                  AutoGenerateColumns="False"
                  ItemsSource="{Binding SelectedItem.MyCollectionView}"
                  CanUserAddRows="False"
                  CanUserDeleteRows="False"
                  CanUserResizeRows="False"
                  CanUserSortColumns="False"
                  SelectionMode="Single"
                  SelectionUnit="FullRow">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}"></DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding Index}"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox Grid.Column="0"
                     Text="{Binding Name1}"></TextBox>
            <TextBox Grid.Column="1"
                     Text="{Binding Index}"></TextBox>
        </Grid>
    </Grid>
</Window>

代码隐藏:

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

namespace WpfApplication4
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            Items = new ObservableCollection<TopGridItem>();
            Items.Add(new TopGridItem { Name = "One" });
            Items.Add(new TopGridItem { Name = "Two" });
            Items.Add(new TopGridItem { Name = "Three" });
        }

        public String Name1 { get; set; }
        public String Index { get; set; }
        public ObservableCollection<TopGridItem> Items { get; private set; }

        public TopGridItem SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                _selectedItem = value;
                OnPropertyChanged("SelectedItem");
                if (_selectedItem != null)
                {
                    _selectedItem.ResetView();
                }
            }
        }
        TopGridItem _selectedItem;

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class TopGridItem : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        public String Name { get; set; }

        public ICollectionView MyCollectionView
        {
            get
            {
                return _myCollectionView;
            }
            set
            {
                _myCollectionView = value;
                OnPropertyChanged("MyCollectionView");
            }
        }
        ICollectionView _myCollectionView;

        public void ResetView()
        {
            MyCollectionView = null;
            ICollectionView _customerView = CollectionViewSource.GetDefaultView(_collection);
            _customerView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
            MyCollectionView = _customerView;
        }

        ObservableCollection<BottomGridItem> _collection;

        public TopGridItem()
        {
            _collection = new ObservableCollection<BottomGridItem>();
            _collection.Add(new BottomGridItem { Name = "bbbbbb" });
            _collection.Add(new BottomGridItem { Name = "aaaaa" });
            _collection.Add(new BottomGridItem { Name = "aaaaa" });
            _collection.Add(new BottomGridItem { Name = "ccccc" });
            _collection.Add(new BottomGridItem { Name = "dddddd" });
            ResetView();
        }
    }

    public class BottomGridItem
    {
        public String Name { get; set; }
        public String Index { get; set; }
    }
}