wpf - 可观察链表

标签 wpf linked-list inotifycollectionchanged

在我的 WPF 应用程序中,我有一个 ItemsControl,其项目值取决于前一项 显示 .

ViewModel 是一个分割成可变长度部分的音频文件,我需要以这种方式显示它,右侧显示一个 DateTime,这就是我需要计算的(我只知道每个部分的长度,我需要计算它开始和结束的实际时间,以及 ItemsControl 上的位置)。

--
  ----
      ------------
                  --
                    --------------------

我的第一种方法是使用 ObservableCollection<MyviewModel>但很快就发生了一些恐怖事件:

5 路多重绑定(bind),其中 IMultiValueConverter我会计算要返回的值并将 DataContext 的属性设置为该值,因为我只知道运行时的前一个元素。

前一个元素是使用 Relativesource.PreviousData 上的绑定(bind)发送的.

现在我的问题是,在从 Converter 设置一个值(这显然是一件坏事)并实际让它工作之后,常规 Collection 在其元素中没有顺序的概念,所以当更进一步时我想在其余部分中间添加一个音频部分,显示困惑。

此外,当我要实现更多业务逻辑时,我可能需要访问在此转换器中计算的音频部分的开始和结束,如果它还没有显示怎么办......?

所以这种方法在几个层面上都是错误的。

那是我开始谷歌搜索并发现LinkedList的地方.现在我正在尝试创建一个基本上是 Observable LinkedList 的类(我不需要它是通用的):
public class ObservableSegmentLinkedList : LinkedList<MyViewModel>, INotifyCollectionChanged
    {
        //Overrides ???

        #region INotifyCollectionChanged Members

        public event NotifyCollectionChangedEventHandler CollectionChanged;
        public void OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, e);
            }
        }

        #endregion
    }

问题的核心是我无法覆盖修改集合的方法(Addfirst、AddLast 等),所以我无法正确调用 OnNotifyCollectionChanged ......

所以我想我可以为这些方法中的每一种方法进行重载,但这听起来很讨厌......

简而言之:我需要某种集合,其中每个项目都知道前一个项目的详细信息,以便计算它自己的一个属性。

有什么线索吗?这甚至是一个好的解决方案吗?

谢谢!

附录,ViewModel 看起来像:
public class MyViewModel : INotifyPropertyChanged
    {
        private DateTime m_SegmentLength;
        public DateTime SegmentLength
        {
            get { return m_SegmentLength; }
            set
            {
                m_SegmentLength = value;
                NotifyPropertyChanged("SegmentLength");
            }
        }

        private DateTime m_SegmentAdvert;
        public DateTime SegmentAdvert
        {
            get { return m_SegmentAdvert; }
            set
            {
                m_SegmentAdvert = value;
                NotifyPropertyChanged("SegmentAdvert");
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String prop)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }

        #endregion
    }

编辑:我想我会尝试结合 Thomas 和 Will 的答案:我将使用组合(即我在我的自定义对象中保留一个 LinkedList 的实例而不是从它继承)并重新定义要使用的方法(AddAfter、AddFirst等),我将在调用实际的 LinkedList 方法后调用 OnNotifyPropertychanged。这有点工作,但我想我的问题不会有任何优雅的解决方案......

最佳答案

好的,我制作了一个支持 IEnumerable 的自定义泛型类并且被用作 LinkedList<T> ,唯一的区别是 WPF 会收到更改通知。

请注意,此解决方案仅适用于相当小的集合,我最多只需要管理大约 30 个元素,所以对我来说没问题,但每次修改此集合时,它都会被视为“重置”。

解决方案如下:

    /// <summary>
    /// This class is a LinkedList that can be used in a WPF MVVM scenario. Composition was used instead of inheritance,
    /// because inheriting from LinkedList does not allow overriding its methods.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ObservableLinkedList<T> : INotifyCollectionChanged, IEnumerable
    {
        private LinkedList<T> m_UnderLyingLinkedList;

        #region Variables accessors
        public int Count
        {
            get { return m_UnderLyingLinkedList.Count; }
        }

        public LinkedListNode<T> First
        {
            get { return m_UnderLyingLinkedList.First; }
        }

        public LinkedListNode<T> Last
        {
            get { return m_UnderLyingLinkedList.Last; }
        }
        #endregion

        #region Constructors
        public ObservableLinkedList()
        {
            m_UnderLyingLinkedList = new LinkedList<T>();
        }

        public ObservableLinkedList(IEnumerable<T> collection)
        {
            m_UnderLyingLinkedList = new LinkedList<T>(collection);
        }
        #endregion

        #region LinkedList<T> Composition
        public LinkedListNode<T> AddAfter(LinkedListNode<T> prevNode, T value)
        {
            LinkedListNode<T> ret = m_UnderLyingLinkedList.AddAfter(prevNode, value);
            OnNotifyCollectionChanged();
            return ret;
        }

        public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
        {
            m_UnderLyingLinkedList.AddAfter(node, newNode);
            OnNotifyCollectionChanged();
        }

        public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
        {
            LinkedListNode<T> ret = m_UnderLyingLinkedList.AddBefore(node, value);
            OnNotifyCollectionChanged();
            return ret;
        }

        public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
        {
            m_UnderLyingLinkedList.AddBefore(node, newNode);
            OnNotifyCollectionChanged();
        }

        public LinkedListNode<T> AddFirst(T value)
        {
            LinkedListNode<T> ret = m_UnderLyingLinkedList.AddFirst(value);
            OnNotifyCollectionChanged();
            return ret;
        }

        public void AddFirst(LinkedListNode<T> node)
        {
            m_UnderLyingLinkedList.AddFirst(node);
            OnNotifyCollectionChanged();
        }

        public LinkedListNode<T> AddLast(T value)
        {
            LinkedListNode<T> ret = m_UnderLyingLinkedList.AddLast(value);
            OnNotifyCollectionChanged();
            return ret;
        }

        public void AddLast(LinkedListNode<T> node)
        {
            m_UnderLyingLinkedList.AddLast(node);
            OnNotifyCollectionChanged();
        }

        public void Clear()
        {
            m_UnderLyingLinkedList.Clear();
            OnNotifyCollectionChanged();
        }

        public bool Contains(T value)
        {
            return m_UnderLyingLinkedList.Contains(value);
        }

        public void CopyTo(T[] array, int index)
        {
            m_UnderLyingLinkedList.CopyTo(array, index);
        }

        public bool LinkedListEquals(object obj)
        {
            return m_UnderLyingLinkedList.Equals(obj);
        }

        public LinkedListNode<T> Find(T value)
        {
            return m_UnderLyingLinkedList.Find(value);
        }

        public LinkedListNode<T> FindLast(T value)
        {
            return m_UnderLyingLinkedList.FindLast(value);
        }

        public Type GetLinkedListType()
        {
            return m_UnderLyingLinkedList.GetType();
        }

        public bool Remove(T value)
        {
            bool ret = m_UnderLyingLinkedList.Remove(value);
            OnNotifyCollectionChanged();
            return ret;
        }

        public void Remove(LinkedListNode<T> node)
        {
            m_UnderLyingLinkedList.Remove(node);
            OnNotifyCollectionChanged();
        }

        public void RemoveFirst()
        {
            m_UnderLyingLinkedList.RemoveFirst();
            OnNotifyCollectionChanged();
        }

        public void RemoveLast()
        {
            m_UnderLyingLinkedList.RemoveLast();
            OnNotifyCollectionChanged();
        }
        #endregion

        #region INotifyCollectionChanged Members

        public event NotifyCollectionChangedEventHandler CollectionChanged;
        public void OnNotifyCollectionChanged()
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (m_UnderLyingLinkedList as IEnumerable).GetEnumerator();
        }

        #endregion
    }

正如@AndrewS 在评论中提到的那样,应该将 LinkedListNode 替换为从其 List 属性返回 ObservableLinkedList 的自定义类。

关于wpf - 可观察链表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6996425/

相关文章:

c - 使用指针和两个结构数组进行桶排序

java - 对 LinkedList 中具有相同值的项目进行排序??? - java

c# - 删除字典中的所有条目 c# WPF

wpf - MVVM:ado.net Entity Framework 和模型

c# - 如何调用派生类的方法?

c# - 如何读取 BitmapSource 四个角的像素?

linked-list - 如何判断链表是否包含循环?

c# - ObservableCollection 如何触发 Replace 操作?

c# - 如何在 ObservableCollection 上引发 CollectionChanged 事件,并将更改的项目传递给它?

c# - 如何在 wpf 用户控件中收听 INotifyCollectionChanged