DataGrid CollectionViewSource Refresh性能问题

在WPF中,CollectionViewSource是一个经常用到的集合类型,主要用于对后台数据排序,条件筛选或分组操作。
     场景:当需要筛选包含“test”的数据项时,我们会分步输入搜索条件,依次为“t”、“te”、“tes”,而最后是“test”,而我们简单的处理经常会是在Textbox的TextChanged事件中直接添加CollectionViewSource的View的Refresh,这样筛选操作实际上进行了四次筛选操作,每一步筛选操作都会Filter及RefreshUI,对于应用来说,前几次的Filter及RefreshUI均是无用的,白白浪费了资源。
     解决方案:
     1:TextChanged中的Refresh操作进行延迟刷新,即用户输入完成后先不进行刷新,超过一定的时间再进行刷新,对于筛选条件,需要一个定时器延迟,(当筛选条件过多时,定时器数量过量,不易管理,易出错)
     2:将延迟做到CollectionViewSource中View的刷新供码中,比如,封装一个方法SourceRefresh,协定刷新_source时只能通过SourceRefresh方法。
private CollectionViewSource _source = new CollectionViewSource();
        private DispatcherTimer timer=new DispatcherTimer();
        public void SourceRefresh()
        {
            if(timer.IsEnabled)
                timer.Stop();
            timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
            timer.Tick += (sender, e) =>
            {
                timer.Stop();
                if (null != _source.View)
                    _source.View.Refresh();
            };
            timer.Start();
        }

  看源码会比较直观点,如下:

  

  下面的代码是我写的例子,可以参考下:

  

public class MyListCollectionView<T> : ListCollectionView
    {
        public MyListCollectionView(IList list) : base(list)
        {
            _filterTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
            _filterTimer.Tick += (sender, e) =>
            {
                CancelAllTimer();
                RefreshFilter();
                _freshUITimer.Start();
                Console.WriteLine("A");
            };
            _freshUITimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
            _freshUITimer.Tick += (sender, e) =>
            {
                CancelAllTimer();
                RefreshUI();
                _freshCurrentTimer.Start();
                Console.WriteLine("B");
            };
            _freshCurrentTimer.Interval = new TimeSpan(0, 0, 0, 0, 20);
            _freshCurrentTimer.Tick += (sender, e) =>
            {
                CancelAllTimer();
                RefreshCurrent();
                Console.WriteLine("C");
            };
        }

        private DispatcherTimer _filterTimer = new DispatcherTimer();
        private DispatcherTimer _freshUITimer = new DispatcherTimer();
        private DispatcherTimer _freshCurrentTimer = new DispatcherTimer();
        private bool _isFreshFilter = false;

        private void CancelAllTimer()
        {
            _filterTimer.Stop();
            _freshUITimer.Stop();
            _freshCurrentTimer.Stop();
        }

        protected override void RefreshOverride()
        {
            _filterTimer.Start();
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
        {
            if (!_isFreshFilter)
                base.OnCollectionChanged(args);
        }

        protected override void OnCurrentChanged()
        {
            if (!_isFreshFilter)
                base.OnCurrentChanged();
        }

        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (!_isFreshFilter)
                base.OnPropertyChanged(e);
        }

        private void RefreshFilter()
        {
            try
            {
                //cancel all
                _isFreshFilter = true;
                base.RefreshOverride();
            }
            finally
            {
                _isFreshFilter = false;
            }
        }

        private void RefreshUI()
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        private void RefreshCurrent()
        {
            OnCurrentChanged();

            OnPropertyChanged("IsCurrentAfterLast");
            OnPropertyChanged("IsCurrentBeforeFirst");
            OnPropertyChanged("CurrentPosition");
            OnPropertyChanged("CurrentItem");
        }

        private void OnPropertyChanged(string proName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(proName));
        }
    }

  public class MyCollection<T> : ObservableCollection<T>, ICollectionViewFactory
    {
        public MyCollection()
        {
        }

        public MyCollection(IList<T> list) : base(list)
        {
        }

        public MyCollection(IEnumerable<T> list) : base(list)
        {
        }

        public MyListCollectionView<T> _view;

        public ICollectionView CreateView()
        {
            _view = new MyListCollectionView<T>(this);
            return _view;
        }
    }

 

 

posted @ 2016-01-06 19:58  magic249  阅读(1641)  评论(0编辑  收藏  举报