实时更改集合的计算(在C#中) [英] Calculation on a realtime changing collection ( in c#)

查看:61
本文介绍了实时更改集合的计算(在C#中)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个不断变化的对象集合(也可以在Collection中添加/删除以及属性更改).

I have a changing collection of changing objects(add/delete in Collection as well as property changes are also possible).

我想通过对该集合进行某种计算来获得一个新的集合(对具有相同字段值的所有对象的某些字段求和/相乘).并将计算出的列表绑定到UI.

I want to get a new collection by some calculation on this Collection (summation / multiplication over some fields of all the objects having same value of a field). And bind calculated list to UI.

例如:因此,我有几种水果的不同质量的比率和数量的列表,现在我想找到一个新列表,其中列出了每种水果的平均比率和每种水果的总量(与质量无关).数量可以在运行时更改,还可以添加更多品质和种类的水果.

for Ex: So I have a list of rate and qty of different qualities of several fruits and now I want to find a new list having avg rate and total quantity of each fruit(irrespective of quality) given that rate & quantity can be changes at run time as well as some more qualities and fruit-species can be added to collection.

现在,如果在运行时第一个列表中的费率或数量发生变化,则更改也应反映在第二个列表中.

Now If rates or quantity changes at runtime in first List changes should be reflected in second list also.

考虑到我们将列表绑定到Datagrid上,请建议应该使用哪些方法来实现它.

Please suggest which methods should be used to achieve it considering we are binding the list to a Datagrid.

推荐答案

有一个名为Buffer的简洁的反应式扩展程序:

There is a neat Reactive Extension called Buffer:

var o = new ObservableCollection<long>();
var s1 = Observable.Interval(TimeSpan.FromMilliseconds(100)).Subscribe(o.Add);
var s2 =
    Observable.FromEventPattern<NotifyCollectionChangedEventArgs>(o, "CollectionChanged")
        .Buffer(TimeSpan.FromMilliseconds(500))
        .Subscribe(
            s =>
            {
                Console.WriteLine("Last received {0}. Current count: {1}", Convert.ToInt64(s.Last().EventArgs.NewItems[0]), o.Count);                            
            });

这将使您能够在发生更改时接收集合更改的事件,但忽略除最后一个事件以外的所有事件.

This will allow you to receive on collection changed events as they occur, but ignore all except the last one.

更新1

一个已知的问题是,更新项目时CollectionChanged不会触发. MSDN文档是完全不正确的.您将必须实现TrulyObservableCollection,但您的数据元素也必须实现INotifyChanged接口.

It is a known issue that CollectionChanged does not fire when items are updated. The MSDN documentation is simply incorrect. You will have to implement a TrulyObservableCollection but your data elements must implement INotifyChanged interface as well.

namespace ConsoleApplication1
{
    #region

    using System;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Linq;
    using System.Reactive.Linq;
    using System.Threading;

    #endregion

    internal class Program
    {
        #region Methods

        private static void Main(string[] args)
        {
            var autoReset = new AutoResetEvent(false);
            var r = new Random();
            var o = new TrulyObservableCollection<DataPoint>();
            var subscription1 = Observable.Interval(TimeSpan.FromSeconds(1)).Take(3).Subscribe(
                i =>
                {
                    o.Add(
                        new DataPoint
                        {
                            ItemCount = r.Next(100)
                        });
                    Console.WriteLine("Fire1 {0}", i);
                });
            var subscription2 =
                Observable.FromEventPattern<NotifyCollectionChangedEventArgs>(o, "CollectionChanged")
                    .Subscribe(s => { Console.WriteLine("List changed. Current total {0}", o.Sum(s1 => s1.ItemCount)); });
            var subscription3 = Observable.Interval(TimeSpan.FromSeconds(1)).Delay(TimeSpan.FromSeconds(3)).Take(3).Finally(
                () =>
                {
                    o.Clear();
                    autoReset.Set();
                }).Subscribe(
                    i =>
                    {
                        if (o.Any())
                        {
                            o[r.Next(o.Count)].ItemCount = r.Next(100);
                            Console.WriteLine("Fire3 {0}", i);
                        }
                    });
            autoReset.WaitOne();
        }

        #endregion

        public class TrulyObservableCollection<T> : ObservableCollection<T>
            where T : INotifyPropertyChanged
        {
            #region Constructors and Destructors

            public TrulyObservableCollection() { CollectionChanged += this.TrulyObservableCollection_CollectionChanged; }

            #endregion

            #region Methods

            private void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.NewItems != null)
                {
                    foreach (Object item in e.NewItems)
                    {
                        (item as INotifyPropertyChanged).PropertyChanged += this.item_PropertyChanged;
                    }
                }
                if (e.OldItems != null)
                {
                    foreach (Object item in e.OldItems)
                    {
                        (item as INotifyPropertyChanged).PropertyChanged -= this.item_PropertyChanged;
                    }
                }
            }

            private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                OnCollectionChanged(a);
            }

            #endregion
        }

        private class DataPoint : INotifyPropertyChanged
        {
            #region Fields

            private int itemCount;

            #endregion

            #region Public Events

            public event PropertyChangedEventHandler PropertyChanged;

            #endregion

            #region Public Properties

            public int ItemCount
            {
                get { return itemCount; }
                set
                {
                    itemCount = value;
                    this.OnPropertyChanged("ItemCount");
                }
            }

            #endregion

            #region Methods

            protected virtual void OnPropertyChanged(string propertyName = null)
            {
                var handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(propertyName));
                }
            }

            #endregion
        }
    }
}

这篇关于实时更改集合的计算(在C#中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆