【问题标题】:WPF ListBox not binding to INotifyCollectionChanged or INotifyPropertyChanged EventsWPF ListBox 未绑定到 INotifyCollectionChanged 或 INotifyPropertyChanged 事件
【发布时间】:2010-11-13 15:53:55
【问题描述】:

我有以下测试代码:

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&lt;SomeItem&gt; 继承。我尝试扮演我自己的INotifyCollectionChanged 而不是使用ObservableCollection 的原因是因为我在真实代码中包装了一个COM 集合。该集合将通知添加/更改/删除,我正在尝试将这些转换为 WPF 的 INotify 事件。

希望这已经足够清楚了(为时已晚)。

【问题讨论】:

  • 我猜这是因为您没有充分实现INotifyCollectionChanged 行为,而且您根本没有实现INotifyPropertyChanged。寻找具体原因可能不值得调查,因为您最好将SomeCollection 更改为从ObservableCollection&lt;T&gt; 继承并为您完成很多工作。为什么要重新发明轮子?如果需要,您仍然可以重写方法来自定义其行为。
  • 您是否获得了有关您要包装的 COM 集合的更多详细信息?我认为您应该问如何将您的 COM 集合转换为 ObservableCollection。

标签: wpf observablecollection inotifypropertychanged inotifycollectionchanged


【解决方案1】:

ObservableCollection&lt;T&gt; 也实现了INotifyPropertyChanged。当您的收藏只是一个 IEnumerable&lt;T&gt; 时,您没有任何要为其创建事件的属性,但 ObservableCollection&lt;T&gt;CountItem[] 属性创建 PropertyChanged 事件。您可以尝试通过从IList&lt;T&gt; 派生并实现INotifyPropertyChanged 来使您的收藏更像ObservableCollection&lt;T&gt;。不过,我不知道这是否能解决您的问题。

【讨论】:

  • 如果我正确理解了这个问题,那么集合已经存在并且有一个不是 ObserverableCollection 的基类。此集合即使实现了 INotifyCollectionChanged,也不会在修改时强制更新列表框。问题是为什么?
【解决方案2】:

我不明白为什么我总是看到人们试图在 WPF 中实现他们自己的集合。只需使用ObservableCollection&lt;SomeItem&gt;,您的所有 CollectionChanged 通知都会得到处理。

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

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

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

【讨论】:

  • 好吧,ObservableCollection 没有实现排序。因此,如果您希望数据以排序方式进行,则需要扩展其他一些集合并实现 INotifyCollectionChanged。
  • @Adarsha 我只是扩展ObservableCollection&lt;T&gt; 以包含Sort 方法。我没有为这种行为创建一个继承自 ObservableCollection&lt;SomeItem&gt; 的类。您可以在this answer 中看到排序代码的示例
  • 请注意,OP 没有扩展 ObservableCollection,而是尝试实现 INotifyCollectionChanged。它希望您实现 OnCollectionChanged。请注意,ObservableCollection.Move 并非在所有版本的 .NET 中都可用,例如视窗电话。所以要实现排序,我们需要重新发明轮子来进行排序。它要么使用实现 IList、INotifyCollectionChanged 的​​类,要么使用 ObservableCollection 并从头开始重新排序。
猜你喜欢
  • 1970-01-01
  • 2011-08-13
  • 1970-01-01
  • 2011-01-13
  • 1970-01-01
  • 2010-11-11
  • 2017-03-30
  • 2011-01-02
  • 2013-07-31
相关资源
最近更新 更多