SortedBindingList.Find

SortedBindingList.Find

Old forum URL: forums.lhotka.net/forums/t/863.aspx


mking posted on Wednesday, August 09, 2006

http://forums.lhotka.net/forums/thread/544.aspx

Hi,

I implemented sorting using the GridView control and the SortedBindingList as described in the above thread.  It works great. 

Now I need to bind a DetailsView control to a specific object in the collection when the user clicks "Edit" on a particular row.  My code looks like this:

    protected void CslaDataSource2_SelectObject(object sender, Csla.Web.SelectObjectArgs e)
    {
        //get the business object for the DetailsView
        e.BusinessObject = GetSelectedEvent();
    }

    private Event GetSelectedEvent()
    {
        SortedBindingList<Event> evts = GetEvents(false);
        if (grdEvents.SelectedValue != null)
        {
            int index = evts.Find("EvtID", (int)grdEvents.SelectedValue);
            return evts[index];
        }
        return null;
    }

I get a Specified method is not supported error inside SortedBindingList.cs.  The line of code where the error happens is:

        return _bindingList.Find(property, key);

Do I need to code a Find method in my EditableRootList class?

Thanks,

Mike

 

 

mking replied on Wednesday, August 09, 2006

More info:

I was able to get the above error to stop happening by adding a FindCore procedure to my BusinessList class.  Then I quickly realized that it was returning the index to my BusinessList, not the SortedBindingList.  Which caused the wrong record to appear in the DetailsView.

So, to try an fix my problems, I'm now using a Session["currentSortObject"] and a Session["currentObject"].  One contains the SortedBindingList and the other contains the associated BusinessList.  It's working properly from the user's perspective but it seems like a hack.

Has anyone posted example code of a fully functional, bound GridView/DetailView that's sortable and editable?  I have the PTWeb example project but it's pretty basic.

Thanks,

Mike

pvanroos replied on Friday, August 18, 2006

Hi Mike,

I'm looking to sort the DetailsView at runtime but haven't found a way to do it.  Did you ever find a solution to this problem?

Thanks,

Paul

RockfordLhotka replied on Saturday, August 19, 2006

The search/find functionality isn't implemented in either BindingList<T> or Csla.SortedBindingList<T>. There is a known bug in SortedBindingList where IndexOf() returns the unsorted value rather than the sorted value - that is being fixed in version 2.1.

It may be that the fix to IndexOf will solve your problem if you are using a feature of List<T>. If you are using a feature of IBindingList (BindingList<T>) then this won't help, because you'd need a list class that implements the search/find behaviors. You could implement such a list as a wrapper much like I did with SortedBindingList and the new FilteredBindingList - making this new list composable with the others.

fmahieux replied on Tuesday, March 13, 2007

Actually, I would like to implement the Find method into my business objects but think it will seat better  into the CSLA Framework with help of generics like :

        public GroupInfo Find(string[] propertyNames, object[] values)

        {

            if (propertyNames == null)

                throw new Exception("No property name is defined.");

            if (values == null)

                throw new Exception("No values are defined.");

            if (propertyNames.Length != values.Length)

                throw new Exception("Number of values does not match count of property names.");

 

            int propertyIndex= 0;

            string propertyName = String.Empty;

            List<PropertyDescriptor> properties = new List<PropertyDescriptor>();

 

            PropertyDescriptorCollection propertyDescriptorCollection = TypeDescriptor.GetProperties(typeof(GroupInfo));

 

            for (propertyIndex = 0; propertyIndex < propertyNames.Length; propertyIndex++)

            {

                propertyName = propertyNames[propertyIndex];

                if(String.IsNullOrEmpty(propertyName))

                    throw new Exception("An empty or null string was provided as property name.");

                try { properties.Add(propertyDescriptorCollection[propertyName]); }

                catch { throw new Exception(String.Format("Property [{0}] does not exist in the object.", propertyName)); }

            }

 

            for (int itemIndex = 0; itemIndex < this.Count; itemIndex++)

            {

                bool itemMatch  = true;

                for (propertyIndex = 0; propertyIndex < properties.Count; propertyIndex++)

                {

                    PropertyDescriptor propertyDescriptor = properties[propertyIndex];

                    object value = values[propertyIndex];

 

                    itemMatch = propertyDescriptor.GetValue(this[itemIndex]).Equals(value);

                    if (!itemMatch)

                        break;

                }

 

                if (itemMatch)

                    return this[itemIndex];

            }

 

            return null;

        }

Regards

RockfordLhotka replied on Tuesday, March 13, 2007

You could also view a find operation as a special case of a filter operation. Then you could use FilteredBindingList to simply create a view of your collection that only shows the matching items.

 

The problem with doing arbitrary Find operations (especially ones that return n items) in a CSLA setting is that the objects you get back belong to a collection. They are child objects, and thus aren’t designed to stand alone out of context.

 

In some cases a Find makes sense, but in many cases you run the risk of doing things to those objects that are illegal.

 

The FilteredBindingList approach avoids that issue, because the objects are left in context. FilteredBindingList is merely a view over the original list (just like SortedBindingList), and so you are automatically prevented from doing illegal things to the objects, because they are still “in context” within their parent collection.

 

Rocky

 

 

From: fmahieux [mailto:cslanet@lhotka.net]
Sent: Tuesday, March 13, 2007 7:38 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] SortedBindingList.Find

 

Actually, I would like to implement the Find method into my business objects but think it will seat better  into the CSLA Framework with help of generics like :

        public GroupInfo Find(string[] propertyNames, object[] values)

        {

            if (propertyNames == null)

                throw new Exception("No property name is defined.");

            if (values == null)

                throw new Exception("No values are defined.");

            if (propertyNames.Length != values.Length)

                throw new Exception("Number of values does not match count of property names.");

 

            int propertyIndex= 0;

            string propertyName = String.Empty;

            List<PropertyDescriptor> properties = new List<PropertyDescriptor>();

 

            PropertyDescriptorCollection propertyDescriptorCollection = TypeDescriptor.GetProperties(typeof(GroupInfo));

 

            for (propertyIndex = 0; propertyIndex < propertyNames.Length; propertyIndex++)

            {

                propertyName = propertyNames[propertyIndex];

                if(String.IsNullOrEmpty(propertyName))

                    throw new Exception("An empty or null string was provided as property name.");

                try { properties.Add(propertyDescriptorCollection[propertyName]); }

                catch { throw new Exception(String.Format("Property [{0}] does not exist in the object.", propertyName)); }

            }

 

            for (int itemIndex = 0; itemIndex < this.Count; itemIndex++)

            {

                bool itemMatch  = true;

                for (propertyIndex = 0; propertyIndex < properties.Count; propertyIndex++)

                {

                    PropertyDescriptor propertyDescriptor = properties[propertyIndex];

                    object value = values[propertyIndex];

 

                    itemMatch = propertyDescriptor.GetValue(this[itemIndex]).Equals(value);

                    if (!itemMatch)

                        break;

                }

 

                if (itemMatch)

                    return this[itemIndex];

            }

 

            return null;

        }

Regards



dg78 replied on Tuesday, January 19, 2010

Hi,

 

I reactivate this thread because I am in the same situation with the error described in the first post.

 

I use the VB version CSLA 3.52 with VB 2008.

 

The error :   Specified method is not supported.

 

occurs in SortedBindingList

 

  ''' <summary>

  ''' Implemented by IList source object.

  ''' </summary>

  ''' <param name="key">Key value for which to search.</param>

  ''' <param name="property">Property to search for the key

  ''' value.</param>

  Public Function Find(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal key As Object) As Integer Implements System.ComponentModel.IBindingList.Find

    If _supportsBinding Then

      Return SortedIndex(_bindingList.Find([property], key))

    Else

      Return -1

    End If

  End Function

 

in  the line    Return SortedIndex(_bindingList.Find([property], key))

 

What can I do to solve that issue ?

 

Another question about SortedBindingList :

A SortedBindingList  is a view of an original list.

Is it possible to have directly only a list that we can sorted and bound to a datagridview without to have an original list ?

 

Thanks

 

Dominique

dg78 replied on Tuesday, January 19, 2010

I found a solution with some searchs in Google at

http://www.eggheadcafe.com/software/aspnet/31881441/sorting-bindinglist-based.aspx

 

My original list was a BindingList :

  Public Shared listRubSyst As New BindingList(Of htRubriExtension)

 

I create a subclass for BindingList :

 

Public Class BindingList2(Of T)

  Inherits BindingList(Of T)

 

  Protected Overloads Overrides ReadOnly Property SupportsSearchingCore() As Boolean

    Get

      Return True

    End Get

  End Property

 

  Protected Overloads Overrides Function FindCore(ByVal prop As PropertyDescriptor, _

                                                  ByVal key As Object) As Integer

    If prop Is Nothing Then

      Throw New ArgumentNullException("prop")

    End If

    For i As Integer = 0 To Count - 1

      Dim item As Object = Me(i)

      If item IsNot Nothing AndAlso Object.Equals(key, prop.GetValue(item)) Then

        Return i

      End If

    Next

    Return -1

  End Function

 

End Class

 

And now the original list is :

  Public Shared listRubSyst As New BindingList2(Of htRubriExtension)

 

Now it is good. The error was in the BindingList.

I don't understand why Microsoft doesn't correct such errors since so many times.

RockfordLhotka replied on Tuesday, January 19, 2010

dg78:

Now it is good. The error was in the BindingList.

I don't understand why Microsoft doesn't correct such errors since so many times.

At this point in time I suspect this is very low priority for Microsoft. BindingList is only used by Windows Forms, and Windows Forms is a legacy technology. So it gets minimum maintenance, and no one should expect any changes beyond keeping it working as-is on new versions of .NET and Windows.

Copyright (c) Marimer LLC