<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                DataGrid控件是一個列表控件, 可以進行過濾,排序等。本文主要針對DataGrid的過濾功能進行分析, 并提供優化方案。 1)DataGrid的過濾過程: ? ?用戶輸入過濾條件 ? ?調用DataGrid的CollectionViewSource的View.Refresh()功能 ? ?DataGrid控件內部調用CollectionView的RefreshOverride方法 ? ?CollectionView會調用CollectionViewSource的Filter回調函數來過濾符合自定義過濾條件的數據 ? ?CollectionView調用內部的OnCollectionChanged和OnCurrentChanged分別更新界面上的數據和當前選中的Item 2)通過分析發現(10W條數據, 實時過濾時UI非常卡,導致用戶輸入過濾字符丟失),調用CollectionViewSource的View.Refresh()的性能損耗主要集中于: ? ?CollectionViewSource.Filter注冊的方法,以及OnCollectionChanged(每次更新都導致ItemContainerGenerator重新構造UI元素) ? ? ? ? 3)優化方向: ? ?減少CollectionViewSource.Filter注冊的方法的耗時(在實時過濾中每個條件的更改都會調用Refresh從而調用Filter方法) ? ?減少OnCollectionChanged調用的次數。 4)具體優化措施: ? ?實例化3個Timer, 分別用于獲取過濾后的數組(調用Filter)、調用OnCollectionChanged、OnCurrentItemChanged。3個timer分別由前一個timer完成時啟動, 形成一個順序操作。每次調用Timer時,先停止后續Timer的執行, 這樣保證在合理的時間間隔里只有一次Refresh完整完成。 5)實現: ? ?下面代碼重載了ObservableCollection, 然后創建自定義的ListCollectionview.使用時只要用CustomCollection聲明列表數據,包裝為CollectionViewSource, 綁定到DataGrid的ItemSource即可。 //聲明數組數據 public CustomCollection<StudyInfoModel> StudyList ? ? ? { ? ? ? ? ? get { return studyList; } ? ? ? } //包裝為CollectionView ? ?<CollectionViewSource Source="{Binding StudyList}" x:Key="StudyListView"> ? ? ? ? ? ? ? <CollectionViewSource.SortDescriptions> ? ? ? ? ? ? ? ? ? <ComponentModel:SortDescription PropertyName="DateTime" Direction="Descending"/> ? ? ? ? ? ? ? </CollectionViewSource.SortDescriptions> ? ? ? ? ? </CollectionViewSource> //綁定到DataGrid <DataGrid?ItemsSource="{BindingMode=OneWay,Source={StaticResourceStudyListView}}" /> ~~~ public class CustomCollectionView<T> : ListCollectionView ~~~ ~~~ { private readonly DispatcherTimer _timerRefreshCalculate = new DispatcherTimer(); private readonly DispatcherTimer _timerRefreshUI = new DispatcherTimer(); private readonly DispatcherTimer _timerRefreshCurrentItem = new DispatcherTimer(); private bool _isRefreshingCalculate = false; private object _oldSelectedItem = null; public CustomCollectionView(IList list) : base(list) { _timerRefreshUI.Interval = new TimeSpan(0, 0, 0, 0, 300); _timerRefreshCurrentItem.Interval = new TimeSpan(0, 0, 0, 0, 500); _timerRefreshCalculate.Interval = new TimeSpan(0, 0, 0, 0, 200); } #region Override Method protected override void OnPropertyChanged(PropertyChangedEventArgs e) { if (_isRefreshingCalculate) { return; } base.OnPropertyChanged(e); } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) { if (_isRefreshingCalculate) { return; } base.OnCollectionChanged(args); } protected override void OnCurrentChanged() { if (_isRefreshingCalculate) { return; } base.OnCurrentChanged(); } protected override void RefreshOverride() { CancelAllRefreshRequest(); StartRefresh(); } #endregion #region Public Method public void CancelAllRefreshRequest() { _timerRefreshCurrentItem.Stop(); _timerRefreshCurrentItem.Tick -= TimerCurrentItem; _timerRefreshUI.Stop(); _timerRefreshUI.Tick -= TimerUI; _timerRefreshCalculate.Stop(); _timerRefreshCalculate.Tick -= TimerCalculate; if (null != this.CurrentItem) { _oldSelectedItem = this.CurrentItem; } SetCurrent(null, -1); } #endregion #region Private Method private void StartRefresh() { _timerRefreshCurrentItem.Stop(); _timerRefreshCurrentItem.Tick -= TimerCurrentItem; _timerRefreshUI.Stop(); _timerRefreshUI.Tick -= TimerUI; _timerRefreshCalculate.Stop(); _timerRefreshCalculate.Tick -= TimerCalculate; //begin to refresh from calculate, so set flag by true. //and it shielded any collection action during the calculating time. //this logic will avoid items are not correct at UI during refresh. _isRefreshingCalculate = true; _timerRefreshCalculate.Tick += TimerCalculate; _timerRefreshCalculate.Start(); } private void RefreshCalculate(CancellationToken? token) { _timerRefreshCalculate.Tick -= TimerCalculate; if (null != token && null != token.Value) { token.Value.ThrowIfCancellationRequested(); } _isRefreshingCalculate = true; base.RefreshOverride(); _isRefreshingCalculate = false; if (null != token && null != token.Value) { token.Value.ThrowIfCancellationRequested(); } } private void RefreshUI() { try { //detach timer _timerRefreshUI.Tick -= TimerUI; base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); //set timer to refresh current item _timerRefreshCurrentItem.Tick -= TimerCurrentItem; _timerRefreshCurrentItem.Tick += TimerCurrentItem; _timerRefreshCurrentItem.Start(); } catch (OperationCanceledException) { return; } } private void RefreshCurrentItem() { _timerRefreshCurrentItem.Tick -= TimerCurrentItem; if (null == this.InternalList || this.InternalList.Count <= 0) { return; } if (null != _oldSelectedItem) { var index = this.InternalList.IndexOf(_oldSelectedItem); if (index != -1) { SetCurrent(_oldSelectedItem, index); } else { SetCurrent(this.InternalList[0], 0); } } else { SetCurrent(this.InternalList[0], 0); } //Set event to update UI base.OnCurrentChanged(); this.OnPropertyChanged("IsCurrentAfterLast"); this.OnPropertyChanged("IsCurrentBeforeFirst"); this.OnPropertyChanged("CurrentPosition"); this.OnPropertyChanged("CurrentItem"); } private void TimerCalculate(object sender, EventArgs e) { _timerRefreshCurrentItem.Stop(); _timerRefreshCurrentItem.Tick -= TimerCurrentItem; _timerRefreshUI.Stop(); _timerRefreshUI.Tick -= TimerUI; try { RefreshCalculate(null); } catch (OperationCanceledException) { } _timerRefreshUI.Interval = new TimeSpan(0, 0, 0, 0, 50 + Math.Min((int)(this.InternalCount / 80), 300)); _timerRefreshUI.Tick += TimerUI; _timerRefreshUI.Start(); } private void TimerUI(object sender, EventArgs e) { RefreshUI(); } private void TimerCurrentItem(object sender, EventArgs e) { RefreshCurrentItem(); } private void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } #endregion } public class CustomCollection<T> : ObservableCollection<T>, ICollectionViewFactory { public CustomCollection() { } public CustomCollection(List<T> list) : base(list) { } public CustomCollection(IEnumerable<T> collection) : base(collection) { } public ICollectionView CreateView() { return new CustomCollectionView<T>(this); } } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看