CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

Forum has moved

New location: CSLA .NET forum


CSLA .NET Resources:
  • CSLA .NET forum
  • CSLA .NET home page
  • Fun with CSLA Databinding, paging and sorting along with IReportTotalRowCount

    This post has 9 Replies | 3 Followers

    Top 500 Contributor
    Posts 22
    mongo Posted: Thu, Apr 12 2007 1:53 PM

    In a web app, I needed paging and sorting to be done on a number of pages.  I wanted something generic and looked at SortedBindingList and FilteredBindingList.  After reading a couple of Rocky's posts and looking at the FilteredBindingList, it became apparent that using FilteredBindingList focuses on individual items rather than the state of the list.  Therefore, I went a little different route.

    I implemented a class that derives from IList<T> and also implements IReportTotalRowCount where T is your business object  This little class first sorts the list handed to it and then applies the filtering based on the passed in SelectObjectArgs. 

    *** I believe that different grids will pass back differing information for the Sort Expression.  The grid I am using (telerik) is clean, but I've seen others (Intersoft) that like to get cute if I remember correctly.  Just a note of caution.  Also, you could make this more generic to recognize when paging is not being requested by looking at SelectObjectArgs and operate accordingly.

    The best part is the wiring of the SelectObjects event off the Csla Datasource control. Assuming I have a list of Customer objects (ReadOnly, BusinessObject, etc.) and a function that retrieves the Customer objects for the page (from db, session, viewstate, etc), the code looks like this:

    CSLADataSource_SelectObject( object sender, Csla.Web.SelectObjectArgs e)
    {
       e.BusinessObject = new SortedAndPagedBindingList< Customer >(GetCustomerCollection(), e);
    }

    Now for the code:


    /// <summary>
    /// SortedAndPagedBindingList:  This class is responsible for taking a List of 'TBase' and returning
    /// a subset of items that are sorted and paged according to the Csla Datasource control. This control also
    /// implements IReportTotalRowCount which is required to support paging within Csla.
    /// </summary>
    /// <typeparam name="TBase">The collection of Csla objects being sorted and paged</typeparam>
    public class SortedAndPagedBindingList<TBase> : List<TBase>, Csla.Core.IReportTotalRowCount
    {
        /// <summary>
        /// _totalRowCount:  This retains the count of the initial list (as opposed to the trimmed down
        /// result set. Used for paging purposes.
        /// </summary>
        private int _totalRowCount = -1;

        /// <summary>
        /// Constructor:  This constructor builds out object list according to the Csla request.
        /// </summary>
        /// <param name="collection">The source list of all items to be considered.</param>
        /// <param name="args">The paging and sorting parameters used against the incoming list</param>
        public SortedAndPagedBindingList(IList<TBase> collection, Csla.Web.SelectObjectArgs args)
            : base(args.MaximumRows)
        {
            // first, grab the total row count for reporting through the IReportTotalRowCount
            _totalRowCount = collection.Count;

            // next, we'll sort the list if requested.

            Csla.SortedBindingList<TBase> sortedList = new Csla.SortedBindingList<TBase>(collection);

            if (args.SortExpression.Length > 0)
                sortedList.ApplySort(args.SortExpression, args.SortDirection);

            // finally, we'll add the page of items requested by SelectObjectArgs
            if (args.StartRowIndex > sortedList.Count - 1)
                return;

            int rowIndex = args.StartRowIndex;

            while ((rowIndex - args.StartRowIndex) < args.MaximumRows && rowIndex < sortedList.Count)
                this.Add(sortedList[rowIndex++]);

        }

     

        #region IReportTotalRowCount Members

        /// <summary>
        /// TotalRowCount - this property returns the total row count for the initial list that passed to the
        /// constructor.
        /// </summary>
        int Csla.Core.IReportTotalRowCount.TotalRowCount
        {
            get { return _totalRowCount; }
        }

        #endregion


    }

    Not Ranked
    Posts 1
    mdurrin replied on Tue, Jul 24 2007 2:08 PM

    Thanks, Mongo.  That worked great.  This was a real headache before I found your code.

    Marc

    Not Ranked
    Posts 9
    miloy001 replied on Sun, Jul 29 2007 9:59 PM

    Thanks, but why e.StartRowIndex and e.MaxRows always = 1 in my test? Any thought?

    I have to modified like this to make it works:

    public class SortedAndPagedBindingList<TBase> : List<TBase>, Csla.Core.IReportTotalRowCount
    {
        private int _totalRowCount = -1;

        public SortedAndPagedBindingList(IList<TBase> collection,  Csla.Web.SelectObjectArgs args)
            : base(collection.count)
        {
            _totalRowCount = collection.Count;

            Csla.SortedBindingList<TBase> sortedList = new Csla.SortedBindingList<TBase>(collection);

            if (args.SortExpression.Length > 0)
                sortedList.ApplySort(args.SortProperty, args.SortDirection);

                   int i;

            for (i=0;i<collection.count;i++)
                this.Add(sortedListIdea [I]);

        }

     

    Not Ranked
    Posts 1
    shaheem replied on Sun, Aug 5 2007 7:36 AM
    Hi,

    I became a member jst to say thankx...i'v just work with csla.net for a few months...so im fairly new and your code helped me heapz :-)

    Shaheem.
    Not Ranked
    Posts 3

    Mongo,

    Thanks for the code. I have implemented it with a slight change (to fix an issue I ran into).

    I modified it from

            if (args.SortExpression.Length > 0)
                sortedList.ApplySort(args.SortExpression, args.SortDirection);

    to

            if (args.SortProperty.Length > 0)
                sortedList.ApplySort(args.SortProperty, args.SortDirection);

    since ApplySort takes the SortProperty as a first argument and not the Expression. It seems like the correct thing to do, do you agree?

    I utilized this in conjunction with telerik's RadGrid control, and ran into an issue sorting in ascending order on a date. I probed further, and looked at SelectObjectArgs.cs. I don't know if it is specific to this control (the telerik RadGrid control), but when I was attempting to sort ascending, the _sortProperty would be set to "PropertyName ASC" which is not a valid property on my object (it should of been "PropertyName"). I changed it from the following:

        public SelectObjectArgs(System.Web.UI.DataSourceSelectArguments args)
        {

          _startRowIndex = args.StartRowIndex;
          _maximumRows = args.MaximumRows;
          _retrieveTotalRowCount = args.RetrieveTotalRowCount;

          _sortExpression = args.SortExpression;
          if (!(string.IsNullOrEmpty(_sortBLOCKED EXPRESSION)
          {
            if (_sortExpression.Length >= 5 &&
              _sortExpression.Substring(_sortExpression.Length - 5) == " DESC")
            {
              _sortProperty = _sortExpression.Substring(0, _sortExpression.Length - 5);
              _sortDirection = ListSortDirection.Descending;

            }
            else
            {
              _sortProperty = args.SortExpression;
              _sortDirection = ListSortDirection.Ascending;
            }
          }
        }

    to

        public SelectObjectArgs(System.Web.UI.DataSourceSelectArguments args)
        {

          _startRowIndex = args.StartRowIndex;
          _maximumRows = args.MaximumRows;
          _retrieveTotalRowCount = args.RetrieveTotalRowCount;

          _sortExpression = args.SortExpression;
          if (!(string.IsNullOrEmpty(_sortBLOCKED EXPRESSION)
          {
            if (_sortExpression.Length >= 5 &&
              _sortExpression.Substring(_sortExpression.Length - 5) == " DESC")
            {
              _sortProperty = _sortExpression.Substring(0, _sortExpression.Length - 5);
              _sortDirection = ListSortDirection.Descending;

            }
            else if (_sortExpression.Length >= 4 &&
                _sortExpression.Substring(_sortExpression.Length - 4) == " ASC")
            {
                _sortProperty = _sortExpression.Substring(0, _sortExpression.Length - 4);
                _sortDirection = ListSortDirection.Ascending;
            }
            else
            {
              _sortProperty = args.SortExpression;
              _sortDirection = ListSortDirection.Ascending;
            }
          }
        }

     

    After making these two changes, presto. Dates now sorted in both ascending and descending order correctly. I don't know if the telerik control is to blame for passing in the addtional " ASC" for the sort expression or if other controls do the same. I figured I would post it here as a potential bug in CSLA in case someone else runs into it. I'll test it with a different Grid (probably the Microsoft Gridview) and see if the sort expression includes the " ASC" or not. I'll post my results.

     

    Mike

    Not Ranked
    Posts 3

    Following up, it appears like the Microsoft GridView does in fact only pass in "PropertyName" instead of "PropertyName ASC" like the telerik RadGrid does for the SortExpression.

    Regardless, would the change in SelectObjectArgs I proposed in the previous post make sense?

    As for the change I made to Mongo's code, I needed to also add a check for null as well.

            if (args.SortProperty != null && args.SortProperty.Length > 0)
                sortedList.ApplySort(args.SortProperty, args.SortDirection);

    Are there any potential issues with either of these changes?

    Thanks,

    Mike

    Top 10 Contributor
    Posts 9,475
    Those seem like good changes, I'll add this to the wish list.

    Rocky

    Not Ranked
    Posts 1
    icereval replied on Mon, Nov 17 2008 7:26 PM
    One more thing incase paging is not used and you still want to use the same binding list.

                if (args.MaximumRows > 0)
                    while ((rowIndex - args.StartRowIndex) < args.MaximumRows && rowIndex < sortedList.Count)
                        this.Add(sortedList[rowIndex++]);
                else
                    while (rowIndex < sortedList.Count)
                        this.Add(sortedList[rowIndex++]);
    Top 75 Contributor
    Posts 111
    swegele replied on Sat, Jun 13 2009 6:41 PM

    Mongo et al,

    I want to implement your in-memory method.  But you don't show how you use what you made on the page...and I am too thick to figure it out.  Can you show me how you implement this on a page?

    Are you using the CSLA datasource or not?

     

    Thanks

    Sean

    Top 75 Contributor
    Posts 111
    swegele replied on Sat, Jun 13 2009 6:44 PM
    Oops I missed the part at the top where you do your select list...sorry
    Page 1 of 1 (10 items) | RSS

    Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
    Email admin@lhotka.net for support.
    Powered by Community Server (Non-Commercial Edition), by Telligent Systems