General Routine that works on a concrete type

General Routine that works on a concrete type

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


Sarosh posted on Wednesday, September 27, 2006

Hi!

I would like to create general routine that works on a concrete type based on the BusinessListBase<T, C>. where I won’t know the type, ‘T’, 'C' until runtime.

How can I achieve this?

e.g. I want to create a BaseMaintForm that will be used for Maintaining all Lookup/Reference Tables.

1] This Form will have a bindingSource, and a dataGridView

2] From the Menu I would like to pass the concerete class e.g. ProjectList  (BusinessListBase<T, C>) to the BaseMaintForm which will then set that to a private variable (field/property) in the constructor

public partial class BaseMaintForm : Form

{

   private object _mainbo; // What type should this be?

   public BaseMaintForm(object mainBO) // What type should this be?

   {

      this._mainbo = mainBO;

      this.mainBindingSource.DataSource = this._mainbo.GetList();

      this.mainDataGridView.DataSource = this.mainBindingSource;

      this._mainbo.BeginEdit()

   }

}

What I can't figure out is what type should I define _mainbo and mainBO as ?

Thanks

Sarosh

 

ajj3085 replied on Wednesday, September 27, 2006

Not sure if this will work, but have you tried:

public partial class BaseMaintForm<T, C> : Form
    where T : BusienssListBase<T, C>, C : BusienssBase<C> {

       private T _mainbo; // What type should this be?

      this._mainbo = mainBO;

      this.mainBindingSource.DataSource = this._mainbo.GetList();

      this.mainDataGridView.DataSource = this.mainBindingSource;

      this._mainbo.BeginEdit()


 }

RockfordLhotka replied on Wednesday, September 27, 2006

Unforutunately generics rarely work with Windows Forms, as the designers don't understand them...

However, there are some interfaces defined by CSLA to help solve this problem. Specifically, the Csla.Core.IEditableBusinessObject interface, which provides access to a number of key properties.

Also, in CSLA 2.1 I added the ISavable interface to allow the creation of a common UI framework that can easily save editable objects (single and collection types).

So mainBO could be IEditableBusinessObject or ISavable, depending on what you need to do with the object. And beneath IEditableBusinessObject is IUndoableObject and beneath that (common to all business classes - editable and readonly) is IBusinessObject.

Sarosh replied on Wednesday, September 27, 2006

Hi!

IEditableBusinessObject does not have .GetList() and .BeginEdit() Methods.

What interface can I use so that I have access to the following PEM's.

GetList()

BeginEdit()

ApplyEdit()

Save()

AddNew()

CanEditObject()

CanAddObject()

CanDeleteObject()

IsDirty

IsValid

Can I use the bindingSource or the dataGridView's PEMS instead of some of the above mentioned PEM's

Thanks

Sarosh

RockfordLhotka replied on Wednesday, September 27, 2006

There is no single interface that provides everything you list in your post. In fact, it isn't possible to have such a single interface, since you are mixing concepts from single objects and collections. I suppose you could create such an interface and just have the single object implementations throw exceptions for the collection-only elements.

If you want a unified interface like you describe, you'll need to define it yourself. You can do this, and create your own base classes that subclass the 7 CSLA base classes. This subclassing concept has been discussed on other threads. Your new base classes could then implement your common interface - which would inherit from all the other interfaces that do include the members you list.

Here's some info on the items in your list:

You shouldn't call BeginEdit, CancelEdit or ApplyEdit directly. You should allow the bindingsource control to do that on your behalf. There is errata regarding this on www.lhotka.net, and there've been threads about this previously on the forum.

The Save() method is in ISavable (in CSLA 2.1), along with a Saved event.

The CanXYZObject() authorization methods are static/Shared, and so can't be part of an interface. I have not figured out a good way to standardize these methods in a nice way - ideas are welcome!

What is GetList()? You mean the method off the IBindingSource interface from a DataSet?

IsDirty and IsValid are included in IEditableBusinessObject in CSLA 2.1.

AddNew() flows from a standard .NET collection interface (either IList or ICollection).

Sarosh replied on Wednesday, September 27, 2006

Hi!

>>You shouldn't call BeginEdit, CancelEdit or ApplyEdit directly

How else can I set the BO for n-level Undo before seeting it to the bindingSource's DataSource.

>>What is GetList()? You mean the method off the IBindingSource interface from a DataSet?

GetList() is the static constructor for the BO e.g.

   /// <summary>
    /// Returns a list of roles.
    /// </summary>
    public static RoleList GetList()
    {
      if (_list == null)
        _list = DataPortal.Fetch<RoleList>
          (new Criteria(typeof(RoleList)));
      return _list;
    }

Am I correct in saying that it will be very difficult to do what I am trying here?

Sarosh

Mark replied on Wednesday, September 27, 2006

Don't worry about n-level undo - the BindingSource will handle that for you.

GetList() - as you've defined - is a static method and can't be part of the interface (see Rocky's remarks about CanXXXObject).

Based on what I've seen in your posts, you should probably retrieve the list externally and then simply pass the object reference to the form via the constructor - probably typed as IEditableBusinessObject.  You can also role your own interface as Rocky explained previously.

What you want to do *can* be done - you just have to understand the limitations of generics with regards to polymorphism.  Coding to an interface will solve the majority of your issues.  You'll have to find some other solution if you need to access static members of the object (possibly pass the values in as additional parameters on the constructor).  For example...

public BaseMaintForm(IEditableBusinessObject obj, bool canAddObject, bool canEditObject, bool canDeleteObject)
{
   //Do whatever
}

 

Sarosh replied on Wednesday, September 27, 2006

Hi!

Thank you all for your ideas.

I will try them out and will post my findings.

Sarosh

xal replied on Thursday, September 28, 2006

Hi!
Just one remark: as long as you don't use inheritance from your generic form, it should work.
If you want to use inheritance, you should go for an approach such as the one I discuss in this post.


Andrés

Copyright (c) Marimer LLC