Re: SortedBindingList<T>

Re: SortedBindingList<T>

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


ozitraveller posted on Saturday, October 27, 2007

Hi

Hoping someone can help me, I want to make my list sortable, but I won't know what the type is until runtime.

This doesn't work

Type t = _obj.GetType();

Csla.SortedBindingList<t> sortedList = new Csla.SortedBindingList<t>(t.GetList(parms));

Any ideas?

Thanks

Marjon1 replied on Saturday, October 27, 2007

This is the way that generics work, you must know the type at compilation not at run time.

It is possible to use generics to have T be a type that you can pass through, but this will depend on where you are using the sorted list.


ozitraveller replied on Sunday, October 28, 2007

I would appreciate some help, I'm a but stuck here with the generics.

I'm trying to make a generic search form that I can pass in a ReadOnlyListBase, and have it just work,

======================================================

This is where I started and it worked fine, until I needed to add sorting. Which is where I got lost.

        private void LoadData(object[] parms)
        {
            try
            {
                if (this.resultsDataGridView.DataSource != null)
                    this.resultsDataGridView.DataSource = null;

                this.resultsDataGridView.DataSource = Microsoft.VisualBasic.Interaction.CallByName(_obj, "GetList", Microsoft.VisualBasic.CallType.Method, parms);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                System.Threading.Thread.CurrentThread.Abort();
            }
        }

======================================================

Then I thought generics might work better because the SortedBindingList wanted the child object.

What I'm trying to do is pass in the type of object and type of child object, where  I have a ReadOnlyListBase: 

public class ClientList : Csla.ReadOnlyListBase<ClientList, ClientInfo>
 

Then I want to call The GetList method and assign a SortedBindingList of the output to a dataGridView datasource.

        LoadData1<QL.View.ClientList, QL.View.ClientInfo>(QL.View.ClientList, QL.View.ClientInfo, parameterValues);

 public static void LoadData1<T, C>(T t, C c, object[] parms)
        {
            object o = Microsoft.VisualBasic.Interaction.CallByName(t.GetType(), "GetList", Microsoft.VisualBasic.CallType.Method, parms);
            Csla.SortedBindingList<t> sortedList = new Csla.SortedBindingList<t>(o);
            this.resultsDataGridView.DataSource = sortedList;
        }

Error 1 'QuickFind.Library.View.ClientList' is a 'type', which is not valid in the given context
Error 2 'QuickFind.Library.View.ClientInfo' is a 'type', which is not valid in the given context
Error 3 The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)
Error 4 The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)

 


 

Thanks

Marjon1 replied on Monday, October 29, 2007

The following should work (C# isn't my primary language):

public static void LoadData1<T, C>(object[] parms)
        {
            object tmpList = Microsoft.VisualBasic.Interaction.CallByName(T, "GetList", Microsoft.VisualBasic.CallType.Method, parms);
            Csla.SortedBindingList<C> sortedList = new Csla.SortedBindingList<C>(
tmpList);
            this.resultsDataGridView.DataSource = sortedList;

        }

The generics portion of the method willl allow you to determine the type, where and when you make the call to this method, and there is no need to actually pass through the list itself as you fetch that yourself. The only other thing that you could do is restrict the types of T & C, but let's make sure this works for you first.The key thing to remember with generics is the T & C in this scendario are types and are to be just like any other type, not as variables.

Let me know how you go!




ozitraveller replied on Monday, October 29, 2007

Hi Marjon

Thanks for the help.

I've put the change in, and I get the following errors

Error 1 'T' is a 'type parameter' but is used like a 'variable' 
Error 2 The best overloaded method match for 'Csla.SortedBindingList<C>.SortedBindingList(System.Collections.Generic.IList<C>)' has some invalid arguments 
Error 3 Argument '1': cannot convert from 'object' to 'System.Collections.Generic.IList<C>' 

I'm passing in :

LoadData1<QL.View.ClientList, QL.View.ClientInfo>(parameterValues);

Marjon1 replied on Monday, October 29, 2007

Here is a method that I'm able to get to compile on my machine, this uses normal reflection instead of the Microsoft.VisualBasic.Interaction.CallByName method that you was using as I didn't have a reference to that in my default C# project. However, this did compile for me.

    public static void LoadData1<T, C >(object[] parms, Type[] paramtypes)
          where T : Csla.ReadOnlyListBase<T,C>
    {
      MethodInfo factoryMethod = typeof(T).GetMethod("GetList", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, paramtypes, null);
      T tmpList = (T)(factoryMethod.Invoke(null, parms));
      Csla.SortedBindingList<C> sortedList = new Csla.SortedBindingList<C>(tmpList);
      this.resultsDataGridView.DataSource = sortedList;
    }

Good luck!

ozitraveller replied on Tuesday, October 30, 2007

Thanks Marjon, that compiled for me too.

But I'm still having problems relating to 'typeof(T).GetMethod("GetList", ', it' doesn't find the method and factoryMethod therefore is null. I did GetMethods and looped through all the methods and it was there!

Maybe something to do with namespaces.

 

ozitraveller replied on Tuesday, October 30, 2007

Thanks Marjon for the hand.

I just wanted to post what finally worked for completeness.

 LoadData1<ClientList, ClientInfo>(parameterValues);

        public void LoadData1<T, C>(object[] parms) where T : Csla.ReadOnlyListBase<T, C>
        {
            Type t = typeof(T);

            MethodInfo methodInfo = t.GetMethod("GetList", System.Reflection.BindingFlags.Static | BindingFlags.Public);

            T tmpList = (T)(methodInfo.Invoke(null, parms));
            Csla.SortedBindingList<C> sortedList = new Csla.SortedBindingList<C>(tmpList);
            this.resultsDataGridView.DataSource = sortedList;
        }

Copyright (c) Marimer LLC