CollectionView WPF的奇怪行为

时间:2014-02-14 09:54:51

标签: c# .net wpf collectionview

我在使用CollectionViews时遇到了一个非常奇怪的行为,并想知道是否有人可以解释我这种行为。

我有一个ObservableCollection,我们称之为_sourcelist。然后我以这种方式创建_sourcelist的几个CollectionView:

CollectionViewSource cvs = new CollectionViewSource() { Source = _sourcelist };
ICollectionView list = cvs.View;

这些CollectionViews每个都使用不同的过滤器和一个没有过滤器的CollectionView(因此代表原始源)。在我的应用程序中,我有一个TabControl,其中每个TabItem包含一个ListBox,其中一个CollectionViews作为ItemsSource。当我知道从源列表中删除一个项目时,带有没有过滤器的CollectionView的ListBox会更新,但包含已过滤的CollectionViews并包含已删除项目的其他ListBox不会更新。因此删除的项目仍保留在ListBoxes中。

现在,奇怪的行为如下: 当我在上面编写的代码后添加以下代码时:

list.CollectionChanged += (o,e) => { };

然后其他ListBox也会更新。 为什么?我的意思是,我刚刚为CollectionChanged事件注册了一个事件处理程序,它什么也没做!


所以,这是我的代码示例。我知道这是一个很大的代码,但它已准备好运行并重现奇怪的行为。

当您运行代码并尝试删除“全部”列表中的项目时,将不会删除已过滤的“30岁以下”或“超过30”列表中的相应项目。现在取消注释ListViewModel中的注释行(它只是一个空的Eventhandler注册),然后将删除已过滤列表中的相应项。

如果您有任何疑问,请咨询! : - )

感谢您对解决问题的兴趣。 : - )

P.S。:RelayCommand来自程序集:Microsoft.TeamFoundation.Controls

MainWindow.xaml:

<Window x:Class="CollectionTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CollectionTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:ListViewModel}">
            <ListBox ItemsSource="{Binding List}" SelectedItem="{Binding Selected}" BorderBrush="Transparent" Margin="0" HorizontalContentAlignment="Stretch"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:PersonViewModel}">
            <TextBlock Margin="5,0" VerticalAlignment="Center" Text="{Binding Name}"/>
        </DataTemplate>
        <Style x:Key="{x:Type TabItem}" TargetType="{x:Type TabItem}">
            <Setter Property="Header" Value="{Binding Name}"/>
        </Style>
    </Window.Resources>
    <DockPanel>
        <Button DockPanel.Dock="Bottom" Name="DeleteButton" Content="Delete" Command="{Binding DeleteCommand}"/>
        <TabControl Name="TabControl" ItemsSource="{Binding Lists}" Padding="0" SelectedItem="{Binding Selected}"/>
    </DockPanel>
</Window>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    private MainViewModel mvm;

    public MainWindow()
    {
        InitializeComponent();

        mvm = new MainViewModel(CreateRepo());
        this.DataContext = mvm;
    }

    private Repository CreateRepo()
    {
        Repository repo = new Repository();

        for (int i = 20; i < 45; i++) 
        {
            Person p = new Person() { Name = "Person" + i, Age = i };
            repo.Add(p);
        }

        return repo;
    }
}

人:

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

    public int Age { get; set; }
}

存储库:

public class Repository
{
    private readonly List<Person> _list;

    public event EventHandler<RepositoryChangedEventArgs> Added;

    public event EventHandler<RepositoryChangedEventArgs> Removed;

    public Repository()
    {
        this._list = new List<Person>();
    }

    public void Add(Person person)
    {
        if (person == null)
        {
            throw new ArgumentNullException("person");
        }

        if (!this._list.Contains(person))
        {
            this._list.Add(person);

            if (this.Added != null)
            {
                this.Added(this, new RepositoryChangedEventArgs(person));
            }
        }
    }

    public void Remove(Person person)
    {
        if (person == null)
        {
            throw new ArgumentNullException("person");
        }

        if (this._list.Contains(person))
        {
            this._list.Remove(person);

            if (this.Removed != null)
            {
                this.Removed(this, new RepositoryChangedEventArgs(person));
            }
        }
    }

    public List<Person> Get()
    {
        return new List<Person>(this._list);
    }
}

public class RepositoryChangedEventArgs : EventArgs
{
    public Person Entity { get; set; }

    public RepositoryChangedEventArgs(Person entity)
    {
        this.Entity = entity;
    }
}

PersonViewModel:

public class PersonViewModel : INotifyPropertyChanged
{
    private Person _person;

    private Repository _repository;

    public string Name
    {
        get
        {
            return this._person.Name;
        }

        set
        {
            if (this._person.Name != value)
            {
                this._person.Name = value;

                this.OnPropertyChanged("Name");
            }
        }
    }

    public int Age
    {
        get
        {
            return this._person.Age;
        }

        set
        {
            if (this._person.Age != value)
            {
                this._person.Age = value;

                this.OnPropertyChanged("Age");
            }
        }
    }

    public PersonViewModel(Person person, Repository repository)
    {
        this._person = person;
        this._repository = repository;
    }

    public void Delete()
    {
        this._repository.Remove(this._person);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string name)
    {
        if (this.PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

ListViewModel:

public class ListViewModel : INotifyPropertyChanged
{
    private IEnumerable _sourceList;

    private ICollectionView _list;

    private PersonViewModel _selected;

    private string _name;

    public ICollectionView List
    {
        get
        {
            return this._list;
        }
    }

    public PersonViewModel Selected
    {
        get
        {
            return this._selected;
        }

        set
        {
            if (this._selected != value)
            {
                this._selected = value;

                this.OnPropertyChanged("Selected");
            }
        }
    }

    public string Name
    {
        get
        {
            return this._name;
        }

        set
        {
            if (this._name != value)
            {
                this._name = value;

                this.OnPropertyChanged("Name");
            }
        }
    }

    public ListViewModel(string name, IEnumerable list)
    {
        this.Name = name;
        this._sourceList = list;
        CollectionViewSource cvs = new CollectionViewSource() { Source = list };
        this._list = cvs.View;

        // cvs.View.CollectionChanged += (o, e) => { }; // uncomment this line to let it work
    }

    public ListViewModel(String name, IEnumerable list, Predicate<object> filter)
        : this(name, list)
    {
        this._list.Filter = filter;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

MainViewModel:

public class MainViewModel : INotifyPropertyChanged
{
    protected ObservableCollection<PersonViewModel> _sourceList;

    protected ObservableCollection<ListViewModel> _lists;

    protected Repository _repository;

    protected Dictionary<Person, PersonViewModel> _dictionary;

    private RelayCommand _deleteCommand;

    private ListViewModel _selected;

    public ListViewModel Selected
    {
        get
        {
            return this._selected;
        }

        set
        {
            if (this._selected != value)
            {
                this._selected = value;

                this.OnPropertyChanged("Selected");
            }
        }
    }

    public RelayCommand DeleteCommand
    {
        get
        {
            if (this._deleteCommand == null)
            {
                this._deleteCommand = new RelayCommand(this.ExecutedDelete, this.CanExecuteDelete);
            }

            return this._deleteCommand;
        }
    }

    public IEnumerable<ListViewModel> Lists
    {
        get
        {
            return this._lists;
        }
    }

    public MainViewModel(Repository repository)
    {
        this._sourceList = new ObservableCollection<PersonViewModel>();
        this._lists = new ObservableCollection<ListViewModel>();
        this._dictionary = new Dictionary<Person, PersonViewModel>();
        this._repository = repository;
        this._repository.Added += this.OnAdded;
        this._repository.Removed += this.OnRemoved;

        this.CreateSourceList(repository);
        this.CreateLists();

        if (this._lists.Count > 0)
        {
            this.Selected = this._lists[0];
        }
    }

    protected void CreateSourceList(Repository repository)
    {
        foreach (Person person in repository.Get())
        {
            PersonViewModel pvm = new PersonViewModel(person, repository);
            this._dictionary.Add(person, pvm);
            this._sourceList.Add(pvm);
        }
    }

    protected void CreateLists()
    {
        this._lists.Add(new ListViewModel("All", this._sourceList));
        this._lists.Add(new ListViewModel("Under 30", this._sourceList,
            delegate(object o)
            {
                PersonViewModel pvm = o as PersonViewModel;

                return (pvm != null && pvm.Age < 30);
            }));
        this._lists.Add(new ListViewModel("Over 30", this._sourceList,
            delegate(object o)
            {
                PersonViewModel pvm = o as PersonViewModel;

                return (pvm != null && pvm.Age > 30);
            }));
    }

    protected void Remove(Person person)
    {
        PersonViewModel pvm = this._dictionary[person];
        this._dictionary.Remove(person);
        this._sourceList.Remove(pvm);
    }

    protected void OnAdded(object sender, RepositoryChangedEventArgs args)
    {
        Person addedPerson = args.Entity;

        if (addedPerson != null)
        {
            PersonViewModel pvm = new PersonViewModel(addedPerson, this._repository);
            this._dictionary.Add(addedPerson, pvm);
            this._sourceList.Add(pvm);
        }
    }

    protected void OnRemoved(object sender, RepositoryChangedEventArgs args)
    {
        Person removedPerson = args.Entity;

        if (removedPerson != null)
        {
            this.Remove(removedPerson);
        }
    }

    private bool CanExecuteDelete(object o)
    {
        return true;
    }

    private void ExecutedDelete(object o)
    {
        PersonViewModel pvm = null;

        if (this.Selected != null && (pvm = this.Selected.Selected) != null)
        {
            pvm.Delete();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

0 个答案:

没有答案