WPF ListBox无法绑定到INotifyCollectionChanged或INotifyPropertyChanged事件。

4
我有以下测试代码:

private class SomeItem
    {
       public string Title{ get{ return "something"; } }
       public bool Completed { get { return false; } set { } }
    }

    private class SomeCollection : IEnumerable<SomeItem>, INotifyCollectionChanged
    {
        private IList<SomeItem> _items = new List<SomeItem>();
        public void Add(SomeItem item)
        {
            _items.Add(item);
            CollectionChanged(this, new 
             NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        #region IEnumerable<SomeItem> Members

        public IEnumerator<SomeItem> GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        #endregion

        #region INotifyCollectionChanged Members

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        #endregion
    }

    private SomeCollection collection = new SomeCollection();

    private void Expander_Expanded(object sender, RoutedEventArgs e)
    {
        var expander = (Expander) sender;
        var list = expander.DataContext as ITaskList;
        var listBox = (ListBox)expander.Content;
        //list.Tasks.CollectionChanged += CollectionChanged;
        collection.Add(new SomeItem());
        collection.Add(new SomeItem());
        listBox.ItemsSource = collection;
    }

以及XAML

<ListBox Name="taskListList" ItemsSource="{Binding}" BorderThickness="0" ItemContainerStyle="{StaticResource noSelectedStyle}" >
    <ListBox.ItemTemplate>
        <DataTemplate>
           <Expander Expanded="Expander_Expanded">
              <Expander.Header>
                <StackPanel Orientation="Horizontal">
                  <TextBlock Text="{Binding Name}" />
                  <TextBox KeyUp="TextBox_KeyUp" Width="200"/>
                  <Button Name="hide" Click="hide_Click">
                      <TextBlock Text="hide" />
                  </Button>
                </StackPanel>
               </Expander.Header>
                  <ListBox Name="taskList" ItemsSource="{Binding}" ItemTemplate=" 
                     {StaticResource taskItem}" />
              </Expander>
         </DataTemplate>
      </ListBox.ItemTemplate>
   </ListBox>

外部列表框在加载时被填充。当展开器被展开时,我设置了内部列表框的ItemsSource属性(我之所以在此处执行此操作而不是使用绑定是因为此操作非常缓慢,我只希望它在用户选择查看项目时才进行)。内部列表框呈现得很好,但实际上它并没有订阅集合的CollectionChanged事件。我尝试过使用ICollection代替IEnumerable,并添加了INotifyPropertyChanged,以及将INotifyCollectionChanged替换为INotifyPropertyChanged。我实际上唯一能够使其工作的方法是砍掉我的SomeCollection类并从ObservableCollection<SomeItem>继承。我尝试自己角色化INotifyCollectionChanged而不是使用ObservableCollection的原因是我正在真正的代码中包装一个COM集合。该集合将在添加/更改/删除时通知,我正在尝试将这些转换为WPF的INotify事件。希望这足够清楚(已经很晚了)。

1
我猜这可能是因为您没有充分实现 INotifyCollectionChanged 行为,并且根本没有实现 INotifyPropertyChanged。找到具体原因可能并不值得去调查,因为你最好只需更改 SomeCollection 继承自 ObservableCollection<T>,让它为您完成大部分工作。何必重复造轮子?如果需要,您仍然可以重写方法以自定义其行为。 - Sean Hanley
你有关于你正在尝试包装的COM集合的更多细节吗?我认为你应该询问如何将你的COM集合转换为ObservableCollection。 - Iain
2个回答

0

ObservableCollection<T> 还实现了 INotifyPropertyChanged。由于您的集合只是一个 IEnumerable<T>,所以您没有任何属性可以创建事件,但是 ObservableCollection<T> 会为 CountItem[] 属性创建 PropertyChanged 事件。您可以尝试通过从 IList<T> 派生并实现 INotifyPropertyChanged 来使您的集合更像 ObservableCollection<T>。虽然我不知道这是否能解决您的问题。


1
如果我理解问题正确,该集合已经存在,并且具有不是ObserverableCollection<T>的基类。即使该集合实现了INotifyCollectionChanged,但在修改时并不会强制更新列表框。问题是为什么? - Martin Liversage

0
我不明白为什么我总是看到人们试图在WPF中实现自己的集合。只需使用一个ObservableCollection<SomeItem>,所有的CollectionChanged通知都会被处理好。
private ObservableCollection<SomeItem> collection = 
    new ObservableCollection<SomeItem>();

如果你想在SomeItem.PropertyChanged上发生某些事情,那么就让SomeItem实现INotifyPropertyChanged

至于为什么你的CollectionChanged没有被触发,那是因为你设置了ItemsSource属性,而不是绑定它。设置它意味着你正在复制collection并将其存储在ListBox.ItemsSource中。绑定它意味着你会告诉ListBox.ItemsSource引用collection作为它的数据。


嗯,ObservableCollection没有实现排序功能。所以如果你想要按照特定顺序排列数据,你需要扩展其他集合并实现INotifyCollectionChanged接口。 - Adarsha
1
@Adarsha 我只是扩展了 ObservableCollection<T> 来包含一个 Sort 方法。我没有创建一个从 ObservableCollection<SomeItem> 继承该行为的类。你可以在这个答案中看到排序代码的示例。 - Rachel
请注意,OP没有扩展ObservableCollection<SomeItem>,而是尝试实现INotifyCollectionChanged。这需要您实现OnCollectionChanged。请注意,ObservableCollection.Move在某些版本的.NET(例如Windows Phone)中不可用。因此,要实现排序,我们需要重新发明轮子进行排序。要么使用实现IList<T>、INotifyCollectionChanged的类,要么使用ObservableCollection并从头开始重新发明排序。 - Adarsha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接