[原] XAF 如何启用ListView Top N records 提升用户使用体验

為了提升用戶使用體驗,特擴展此功能(來源與Xafari Framework)。
1.可在模型編輯器中設置是否啓用,默認啓用。
2.DataAccessMode為Client模式才啓用。其它模式自動關閉。
3.詳見代碼。

4.當有篩選條件時有Bug,還有待解決,才能上綫使用!

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace CommonModule.ListViewControl.PartialLoadListView
{
    [DefaultValue(1000)]
    public enum PartSize
    {
        //[Description("100")]
        //Rec100,
        //[Description("250")]
        //Rec250,
        //[Description("500")]
        //Rec500,
        [Description("1000")]
        Rec1000,
        //[Description("2500")]
        //Rec2500,
        [Description("5000")]
        Rec5000,
        [Description("All")]
        RecAll
    }

    public enum LoadingBehavior
    {
        Refresh,
        LoadPart,
        LoadAll
    }

    public enum ItemsStringId
    {
        StringTop,
        StringAll,
        StringAllShown,
        StringTopShown,
        StringRecords
    }   

    public interface IModelListViewXafari : IModelNode,IModelExtender
    {
        [Category("Data"), DefaultValue(true), Description("If set to true, partial loading will be used.")]
        bool TopReturnedObjectsChangingEnabled
        {
            get;
            set;
        }       
    }

    [DomainLogic(typeof(IModelListViewXafari))]
    public static class IModelListViewXafariLogic
    {
        public static bool TopReturnedObjectsChangingEnabled(this IModelListView modelListView)
        {
            return ((IModelListViewXafari)modelListView).TopReturnedObjectsChangingEnabled;
        }        
    }    
}
using CommonModule.ListViewControl.PartialLoadListView;
using DevExpress.Data;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.SystemModule;
using DevExpress.ExpressApp.Templates;
using DevExpress.ExpressApp.Utils;
using DevExpress.ExpressApp.Win.Editors;
using DevExpress.ExpressApp.Xpo;
using DevExpress.Utils;
using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace CommonModule.ListViewControl.PartialLoadListView
{
    public class PartialLoadListViewController : ViewController<DevExpress.ExpressApp.ListView>, IModelExtender
    {
        private const string limitImage = null;
        private const string allImage = null;
        private int _partSize;
        private ChoiceActionItem _setPartSizeItem;
        private XPCollection _collection;
        private CollectionSourceBase _collectionSource;
        private bool _allShown;
        private int _records;
        private int _partCountCore = 1;
        private IContainer components;
        private SingleChoiceAction partLoadAction;
        public int PartCount
        {
            get
            {
                return this._partCountCore;
            }
        }
        public PartialLoadListViewController()
        {
            this.InitializeComponent();
            base.RegisterActions(this.components);
            base.TargetViewType = DevExpress.ExpressApp.ViewType.ListView;
            this.SetupItems();
        }
        protected override void OnActivated()
        {
            this.partLoadAction.Active.SetItemValue("Active", false);
            if (base.View != null && base.View.Model.DataAccessMode != CollectionSourceDataAccessMode.Client)
            {
                return;
            }
            if (this.GetModelListView() == null)
            {
                return;
            }
            base.OnActivated();

            this.SetupAppearance();
        }
        private void ViewOnControlsCreated(object sender, EventArgs eventArgs)
        {
            GridView gridView = this.GetGridView();
            this.InitCollection();
            this._collection.LoadingEnabled = false;
            this._collectionSource.TopReturnedObjects = 0;
            this._collectionSource.Sorting.Clear();
            gridView.BeginSort();
            foreach (GridColumn gridColumn in gridView.Columns)
            {
                if (gridColumn.SortOrder != ColumnSortOrder.None)
                {
                    if (gridColumn.SortOrder == ColumnSortOrder.Ascending)
                    {
                        this._collectionSource.Sorting.Add(new SortProperty(PartialLoadListViewController.PropertyName(gridColumn), SortingDirection.Ascending));
                    }
                    else
                    {
                        this._collectionSource.Sorting.Add(new SortProperty(PartialLoadListViewController.PropertyName(gridColumn), SortingDirection.Descending));
                    }
                }
            }
            gridView.EndSort();
            this._collectionSource.TopReturnedObjects = this._records;
            this._collection.LoadingEnabled = true;
        }

        private IModelListViewXafari GetModelListView()
        {
            IModelListViewXafari modelListViewXafari = base.View.Model as IModelListViewXafari;
            if (modelListViewXafari == null || !modelListViewXafari.TopReturnedObjectsChangingEnabled)
            {
                return null;
            }
            this._records = base.View.Model.TopReturnedObjects;
            return modelListViewXafari;
        }
        private void SetupAppearance()
        {
            this.partLoadAction.PaintStyle = ActionItemPaintStyle.CaptionAndImage;
            if (base.View.Model.TopReturnedObjects != 0)
            {
                this.SetImageAndCaptionToLimitShow();
            }
            else
            {
                this.SetImageAndCaptionToShowAllRecords();
            }
            this.partLoadAction.Active.SetItemValue("Active", true);
        }
        protected override void OnViewControlsCreated()
        {
            base.OnViewControlsCreated();
            base.View.CurrentObjectChanged += new EventHandler(this.ViewOnCurrentObjectChanged);
            this.InitCollection();
            GridView gridView = this.GetGridView();
            if (gridView != null)
            {
                gridView.Click += new EventHandler(this.GridViewOnClick);
            }
        }
        private static string PropertyName(GridColumn column)
        {
            IGridColumnModelSynchronizer gridColumnInfo = PartialLoadListViewController.GetGridColumnInfo(column);
            if (gridColumnInfo == null)
            {
                return column.FieldName;
            }
            return gridColumnInfo.PropertyName;
        }

        private static IGridColumnModelSynchronizer GetGridColumnInfo(GridColumn column)
        {
            if (column != null && column.View is IModelSynchronizersHolder)
            {
                return ((IModelSynchronizersHolder)column.View).GetSynchronizer(column) as IGridColumnModelSynchronizer;
            }
            return null;
        }
        private void GridViewOnClick(object sender, EventArgs eventArgs)
        {
            if (this._allShown || this._collectionSource.Sorting == null)
            {
                return;
            }
            MouseEventArgs mouseEventArgs = eventArgs as MouseEventArgs;
            if (mouseEventArgs == null || mouseEventArgs.Button != MouseButtons.Left)
            {
                return;
            }
            GridView gridView = sender as GridView;
            if (gridView.IsSizingState)
            {
                return;
            }
            GridHitInfo gridHitInfo = gridView.CalcHitInfo(mouseEventArgs.Location);
            if (gridHitInfo.HitTest == GridHitTest.ColumnFilterButton)
            {
                return;
            }
            if (gridHitInfo.InColumn)
            {
                this._collection.LoadingEnabled = false;
                this._collectionSource.TopReturnedObjects = 0;
                if (this._collectionSource.Sorting != null)
                {
                    this._collectionSource.Sorting.Clear();
                }
                else
                {
                    this._collectionSource.Sorting = new List<SortProperty>();
                }
                gridView.BeginSort();
                foreach (GridColumn gridColumn in gridView.Columns)
                {
                    gridColumn.SortOrder = ColumnSortOrder.None;
                }
                if (gridHitInfo.Column.SortOrder == ColumnSortOrder.None || gridHitInfo.Column.SortOrder == ColumnSortOrder.Descending)
                {
                    this._collectionSource.Sorting.Add(new SortProperty(PartialLoadListViewController.PropertyName(gridHitInfo.Column), SortingDirection.Ascending));
                    gridHitInfo.Column.SortOrder = ColumnSortOrder.Ascending;
                }
                else
                {
                    this._collectionSource.Sorting.Add(new SortProperty(PartialLoadListViewController.PropertyName(gridHitInfo.Column), SortingDirection.Descending));
                    gridHitInfo.Column.SortOrder = ColumnSortOrder.Descending;
                }
                gridView.EndSort();
                this._collectionSource.TopReturnedObjects = this._records;
                this._collection.LoadingEnabled = true;
                base.ObjectSpace.Refresh();
                DXMouseEventArgs.GetMouseArgs(mouseEventArgs).Handled = true;
            }
        }

        private GridView GetGridView()
        {
            GridListEditor gridListEditor = base.View.Editor as GridListEditor;
            if (gridListEditor == null || gridListEditor.GridView == null)
            {
                return null;
            }
            return gridListEditor.GridView;
        }
        private void ViewOnCurrentObjectChanged(object sender, EventArgs eventArgs)
        {
            base.View.CurrentObjectChanged -= new EventHandler(this.ViewOnCurrentObjectChanged);
            int topReturnedObjects = base.View.Model.TopReturnedObjects;
            if (topReturnedObjects == 0)
            {
                this.SetImageAndCaptionToShowAllRecords();
                this._allShown = true;
                return;
            }
            this._partSize = topReturnedObjects;
            this.SetImageAndCaptionToLimitShow();
            this.SetPartSize();
            this.ResetPartCount();
            this.UpdateCollection(LoadingBehavior.LoadPart);
        }
        private void SetPartSize()
        {
            if (!(base.View.Model is IModelListViewXafari))
            {
                return;
            }
            this._partSize = base.View.Model.TopReturnedObjects;
        }
        private void InitCollection()
        {
            this._collectionSource = base.View.CollectionSource;
            ProxyCollection proxyCollection = this._collectionSource.Collection as ProxyCollection;
            if (proxyCollection == null)
            {
                return;
            }
            this._collection = (XPCollection)proxyCollection.OriginalCollection;
        }
        private void ResetPartCount()
        {
            this._partCountCore = 1;
        }
        private void UpdatePartCount()
        {
            this._partCountCore++;
        }
        private void UpdateCollection(LoadingBehavior behavior)
        {
            if (this._collection == null)
            {
                this.InitCollection();
            }
            try
            {
                this._collection.LoadingEnabled = false;
                Type type = base.View.ObjectTypeInfo.Type;
                decimal value = Convert.ToDecimal(((XPObjectSpace)base.ObjectSpace).Session.Evaluate(type, CriteriaOperator.Parse("Count()", new object[0]), XPObjectSpace.CombineCriteria(this._collectionSource.Criteria.GetValues().ToArray())));
                int num;
                if (behavior != LoadingBehavior.LoadAll && (this._partCountCore == 1 || behavior == LoadingBehavior.Refresh))
                {
                    num = this._records;
                }
                else if (behavior == LoadingBehavior.LoadAll)
                {
                    num = (int)value;
                    this._records = num;
                }
                else
                {
                    if (this._partSize == 0)
                    {
                        this._partSize = this._records;
                    }
                    this._records += this._partSize;
                    num = this._records;
                }
                this._collectionSource.TopReturnedObjects = num;
                if (behavior != LoadingBehavior.Refresh)
                {
                    base.View.ObjectSpace.Refresh();
                }
                this._collection.LoadingEnabled = true;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.ToString());
            }
        }
        private void SetupItems()
        {
            this.partLoadAction.Items.Clear();
            this.FillItemWithEnumValues(typeof(PartSize));
        }
        private void FillItemWithEnumValues(Type enumType)
        {
            IEnumerator enumerator = Enum.GetValues(enumType).GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    object current = enumerator.Current;
                    PartSize enumValue = (PartSize)current;
                    ChoiceActionItem choiceActionItem = new ChoiceActionItem(Guid.NewGuid().ToString(), current);
                    choiceActionItem.ImageName = ImageLoader.Instance.GetEnumValueImageName(current);
                    choiceActionItem.Caption = ((DescriptionAttribute)Attribute.GetCustomAttribute(typeof(PartSize).GetFields(BindingFlags.Static | BindingFlags.Public).Single((FieldInfo x) => (PartSize)x.GetValue(null) == enumValue), typeof(DescriptionAttribute))).Description;
                    this.partLoadAction.Items.Add(choiceActionItem);
                    if (current.ToString() == "RecAll")
                    {
                        choiceActionItem.BeginGroup = true;
                    }
                }
            }
            finally
            {
                IDisposable disposable = enumerator as IDisposable;
                if (disposable != null)
                {
                    disposable.Dispose();
                }
            }
        }
        private void partLoadAction_Execute(object sender, SingleChoiceActionExecuteEventArgs e)
        {
            if (e.SelectedChoiceActionItem.ParentItem != this._setPartSizeItem)
            {
                if (e.SelectedChoiceActionItem.Caption == "顯示更多")
                {
                    this.UpdatePartCount();
                    this.UpdateCollection(LoadingBehavior.LoadPart);
                    this.SetImageAndCaptionToLimitShow();
                }
                return;
            }
            ChoiceActionItem choiceActionItem = this.partLoadAction.Items.FirstOrDefault((ChoiceActionItem a) => a.Id == "顯示更多");
            if (e.SelectedChoiceActionItem.Caption == "All")
            {
                if (DialogResult.OK != MessageBox.Show("這個操作比較耗時,建議你請先設置查詢條件再執行次操作,確定執行?", "警告!",
                    MessageBoxButtons.OKCancel, MessageBoxIcon.Warning))
                    return;

                this.SetImageAndCaptionToShowAllRecords();
                this.UpdateCollection(LoadingBehavior.LoadAll);
                this.partLoadAction.ToolTip = "顯示所有記錄";//XafariWinLocalizer.Active.GetLocalizedString(ItemsStringId.StringAllShown);
                this._allShown = true;
                if (choiceActionItem != null)
                {
                    choiceActionItem.Enabled.SetItemValue("Enabled", false);
                }
                return;
            }
            int num = Convert.ToInt32(e.SelectedChoiceActionItem.Caption);
            base.View.Model.TopReturnedObjects = num;
            this._partSize = num;
            this.ResetPartCount();
            this._records = this._partSize;
            this.UpdateCollection(LoadingBehavior.LoadPart);
            if (choiceActionItem != null)
            {
                choiceActionItem.Enabled.SetItemValue("Enabled", true);
            }
            this.SetImageAndCaptionToLimitShow();
            this._allShown = false;
        }
        protected override void OnDeactivated()
        {
            GridView gridView = this.GetGridView();
            if (gridView != null)
            {
                gridView.Click -= new EventHandler(this.GridViewOnClick);
            }
            base.OnDeactivated();
        }
        private void SetImageAndCaptionToShowAllRecords()
        {
            this.partLoadAction.ImageName = null;
            this.partLoadAction.Caption = "All";// XafariWinLocalizer.Active.GetLocalizedString(ItemsStringId.StringAll);
            this.partLoadAction.ToolTip = "顯示所有記錄";//XafariWinLocalizer.Active.GetLocalizedString(ItemsStringId.StringAllShown);
        }
        private void SetImageAndCaptionToLimitShow()
        {
            this.partLoadAction.ImageName = null;
            this.partLoadAction.Caption = string.Format("{0} {1} ", "僅顯示前", this._records);
            this.partLoadAction.ToolTip = string.Format("{0} {1} {2}.", "僅顯示前", this._records, "條記錄");
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing && this.components != null)
            {
                this.components.Dispose();
            }
            base.Dispose(disposing);
        }
        private void InitializeComponent()
        {
            this.components = new Container();
            this.partLoadAction = new SingleChoiceAction(this.components);
            this.partLoadAction.ItemType = SingleChoiceActionItemType.ItemIsOperation;
            this.partLoadAction.Caption = "部分顯示";
            this.partLoadAction.ConfirmationMessage = null;
            this.partLoadAction.EmptyItemsBehavior = EmptyItemsBehavior.None;
            this.partLoadAction.Id = "partLoadAction";
            this.partLoadAction.PaintStyle = ActionItemPaintStyle.CaptionAndImage;
            this.partLoadAction.ShowItemsOnClick = true;
            this.partLoadAction.ToolTip = string.Empty;
            this.partLoadAction.Execute += new SingleChoiceActionExecuteEventHandler(this.partLoadAction_Execute);
        }
        public void ExtendModelInterfaces(DevExpress.ExpressApp.Model.ModelInterfaceExtenders extenders)
        {
            extenders.Add<IModelViews, IModelListViewXafari>();
            extenders.Add<IModelListView, IModelListViewXafari>();
        }
    }

}
原文地址:https://www.cnblogs.com/Tonyyang/p/5063607.html