WPF ListBox未绑定到INotifyCollectionChanged或INotifyPropertyChanged事件

时间:2009-07-24 08:01:39

标签: wpf observablecollection inotifypropertychanged inotifycollectionchanged

我有以下测试代码:

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事件。

希望这很清楚(已经很晚了)。

2 个答案:

答案 0 :(得分:0)

ObservableCollection<T>也实现了INotifyPropertyChanged。由于您的收集只是IEnumerable<T>,因此您没有任何属性可以为其创建事件,但ObservableCollection<T>PropertyChangedCount属性创建Item[]个事件。您可以尝试通过派生ObservableCollection<T>并实施IList<T>来使您的收藏更像INotifyPropertyChanged。不过,我不知道这是否能解决你的问题。

答案 1 :(得分:0)

我不明白为什么我一直看到人们试图在WPF中实现自己的集合。只需使用ObservableCollection<SomeItem>即可完成所有CollectionChanged通知。

private ObservableCollection<SomeItem> collection = 
    new ObservableCollection<SomeItem>();

如果您想在SomeItem.PropertyChanged上发生某些事情,请SomeItem实施INotifyPropertyChanged

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