Designer Support

Posts   
1  /  2
 
    
rhorner
User
Posts: 5
Joined: 19-May-2004
# Posted on: 10-Nov-2004 14:41:18   

A couple of Ideas I wanted to bounce off the LLBLgen community and maybe get some feedback from you Frans. Is their anyway to add designer support to the generated classes? I would like to be able to drag and drop an entity or a Collection from my toolbox onto a designer and then set some of the properties at design time. How would you approach this? Create custom templates using the component model classes?

I am also working on a control that would server as a Collection Navbar that would allow you to bind controls like in VS2005 to the current entity in Collection Navbar. In concept the Navbar would provide the facilities to navigate, Add, Save and Delete records in a collection. I am just starting to build this component...Actually it is a control and a component. I am using the Implements IExtenderProvider interface to allow any Control with a text or value property to get provided additional properties from the current entity in the NavBar. Kind of like the tooltip appears to add properties to all controls on a form. If anyone has any ideas comments or suggestions I welcome them.

Thanks,

rhorner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 10-Nov-2004 16:56:58   

rhorner wrote:

A couple of Ideas I wanted to bounce off the LLBLgen community and maybe get some feedback from you Frans. Is their anyway to add designer support to the generated classes? I would like to be able to drag and drop an entity or a Collection from my toolbox onto a designer and then set some of the properties at design time. How would you approach this? Create custom templates using the component model classes?

I gave up on that, after weeks of utterly frustration. Somewhere VS.NET makes a call to a method which is not there or something, the only error I get is: "Specified method is not supported". Nothing further. This error pops up when you select the DataMember in the properties grid. I mailed Microsoft about it, back in september, they said they would look into it, get back to me with examples/docs but nothing has showed up. I asked them from time to time, but nothing is returned.

This morning I got ICustomTypeDescriptor working so I made one last (frustrating) try, no luck, same error. Googling on it, I find a couple of people with EXACT the same problem and no answers.

No-one knows apparently what is going on when you click the DataMember drop down. If only I knew what interfaces on which objects it is checking, but this is almost undoable to find out, as debugging this kind of code is impossible. There is also no example. The only thing which apparently works is datasets and pure reflection on raw properties. Nothing in between with ITypedList and IBindingList, 2 interfaces I implemented completely and which do work in normal scenario's but not in this one apparently...

And even reflection SHOULD work. An empty customer collection, provides the properties of the Customer entity including for example the property descriptor for 'Orders' which is a collection. It should enlist that in the DataMember list, but instead it gives a stupid error no-one can use. rage

In 2005 it apparently is better, but as with everything with Microsoft: when you do something more advanced than Joe Sixpack would, it's either misery or not possible and 'fixed' in the 'next release'.

Frans Bouma | Lead developer LLBLGen Pro
rhorner
User
Posts: 5
Joined: 19-May-2004
# Posted on: 10-Nov-2004 18:26:20   

I have run into the same problems but if you are interested I can send you some screenshots of what I have and see if it makes sense what I am trying to accomplish...Where would I send them to? Hope all is well and would like to get some more feedback from you if you have the time.

Thanks,

Rhorner

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 10-Nov-2004 18:56:04   

Thanks! just send it to support AT llblgen.com and it will be fine simple_smile thanks for the effort!

Frans Bouma | Lead developer LLBLGen Pro
jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 10-Nov-2004 20:33:56   

Frans,

Sent you a zip file with a sample of a working business object with designer support, I see a few issues with Adpater class in making it work, I think I'm going to change my methodology of just tweaking the Entity Classes and make a seperate component class that uses the LLBLGen components, due to some issues with exposing Factory created collections.

The sample includes how to make fields show up in the datamember drop down.

John

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 10-Nov-2004 20:51:12   

Thanks a lot John! I'll have a look at it! simple_smile

Frans Bouma | Lead developer LLBLGen Pro
rhorner
User
Posts: 5
Joined: 19-May-2004
# Posted on: 11-Nov-2004 14:49:28   

John,

Would you care to share what you have with other LLBLgen users? you can email it to me if that is convenient at rhorner AT nuair DOT com.

Thanks,

rhorner

jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 11-Nov-2004 20:47:08   

Go to www.ftponline.com and enter vs0306bw as the locator code, it will give you a c# project that has a business object / component that works properly in Visual Studio, I am close to having a set of mods I believe that will work, I just need some more tables to test with.

This is much easier with Self Servicing, I am having to do some work arounds because of the factories for EntityCollections with Adapter (which is what I use), what I have now should work with an existing Task Processor and a new template, but I won't be happy until its perfect stuck_out_tongue_winking_eye

John

jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 11-Nov-2004 23:47:02   

OK,

I have created a piece of code that wraps up stuff in a component, it has one thing I don't really like but it works so I am going to go for it.

I am willing to share the code with someone who has the time to turn it into a template to add to the third party stuff like my SQL Logger stuff. I just am under a deadline and don't have time to do the last mile to wrap it up, or track down my one final workaround.

The todo list: 1) Create a task performer that creates a 'ComponentClasses' folder 2) Convert my code into a template (should be super easy) 3) Create a config that calls the new performer for each entity

Known issues: 1) Each control shows up in the datasource dropdown twice (why? I have no friggin clue) 2) I would like to get rid of GetCollection(), but it works for use with the adapter so its my one cludge.

My code as is works 100% with the Pubs database as my test DB, I don't believe I have used any DB specific code, but I only implemented it for the Adapter.

By adding the LLBLGen DB Specific DLL to the toolbox it shows a component for each Entity Collection, you can drag and drop them to the component area, then select any data aware control and choose it as a datasource, stuff like combos give you a full field list excluding the inner collections.

This gives you design time support for fields etc.

At runtime in form constructer I put:

Adapter.FetchEntityCollection(authorsComponent1.GetCollection(), null);

and poof it fills the component with data and life is good, I'm sure there is some more tweaks that could be done but this should give us a good foundation to start from for the Adapter.

John

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 12-Nov-2004 10:43:52   

Great work! simple_smile

What I have been struggling with is the DataMember dropdown for grids. It always crashes on me, no matter what I implement. Does your code work with that too?

You can send the stuff to me, I'll be working on design time code this weekend as well. (going to implement IComponent, IListSource, ICustomTypeDescriptor and other nasties on all the classes where appropriate) to see if I can fix this thing once and for all.

If you could give me a hint how to check if code is in design mode (so code can create empty instances), I'd be very happy and also how to debug this kind of code (I heard about 2 vs.net instances but I'm not sure how to set it up precisely).

Thanks!

Frans Bouma | Lead developer LLBLGen Pro
jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 12-Nov-2004 14:36:29   

I'm sending off my project to you, the new code is all contained within the ComponentClasses folder, one file per EntityCollection.

I am not going to claim this is how I would engineer this if I had unlimited time, in fact this is not really what I want, but it is an adaptation of what I want for LLBLGen objects, what I want is for MY business objects which encapsulate yours to be IComponent, and this code demonstrates how to wrapper them =)

To answer some of your questions:

Yes this shows DataMembers properly

I originally started with modifications to your EntityClasses object but I did not see a clear and intuitive way to do type specific collections at runtime using a single component.

This solution was done to be minimalistic modifications to LLBLGen standard code and be tacked on with a Task Performer since I considered it optional, again because I don't want LLBLGen components to be IComponent but mine.

Debugging does require 2 copies, I did it at one point, I could try and reset it up again if you need specifics, but as you will see there is very little code in making this work properly.

In addition I really dislike the whole GetCollection method, but I don't see a way around needing to access the collection directly to hand off to the Adapter object since IListSource etc all work with IList and not your interface. That call could probably be modified to pass back the Interface to the collection rather than the collection itself to discourage direct access, or the component object could be expanded to reflect/override some of the base classes, but again I went with the minimalistic approach, and leveraged your work.

If anyone knows why datasources appear twice in the dropdowns I would love to know, also I am assuming there is another Attribute that needs to be applied for collections within collections, but as we know 'Great Documentation!'.

John

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 12-Nov-2004 16:29:25   

jtgooding wrote:

To answer some of your questions:

Yes this shows DataMembers properly

Ok, that's a start, this crashes sometimes for me simple_smile Does it work on northwind as well? (haven't tried yet)

Debugging does require 2 copies, I did it at one point, I could try and reset it up again if you need specifics, but as you will see there is very little code in making this work properly.

I think I can find somewhere on google the answer. What I want to know is how I can debug it because I want to create instances at the right spot, which is kind of hard without documentation wink . But it's a common thing, debugging design time controls, so there must be a tutorial somewhere wink

In addition I really dislike the whole GetCollection method, but I don't see a way around needing to access the collection directly to hand off to the Adapter object since IListSource etc all work with IList and not your interface. That call could probably be modified to pass back the Interface to the collection rather than the collection itself to discourage direct access, or the component object could be expanded to reflect/override some of the base classes, but again I went with the minimalistic approach, and leveraged your work.

You did this to get live data at design time?

Frans Bouma | Lead developer LLBLGen Pro
jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 12-Nov-2004 17:18:37   

I've not tried it on Northwind but I added the code to about 150 of our 900 tables so far and its not failed. I could test it on more if it was a template etc, but oh well stuck_out_tongue_winking_eye

I did this because this statement:

Adapter.FetchEntityCollection(authorsComponent1, null);

returns a Factory error because I believe that AuthorsComonent1 only returns an IList not your interface, and replacing it with:

Adapter.FetchEntityCollection(authorsComponent1.GetCollection(), null);

runs as expected, again its a little bit of a kludge but I only had so much time to play with it.

To get design time data, I'm pretty sure you have to implement IDataProvider interface and going down that path is a fair amount of work.

Useful Link I found: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/pdc_vsdescmp.asp

bertcord avatar
bertcord
User
Posts: 206
Joined: 01-Dec-2003
# Posted on: 12-Nov-2004 17:36:31   

I might be able to help out also. I have been working for the past few months on ASP.Net Server Controls based on entities. I am almost finished and I will send you a sample soon.

Otis wrote:

If you could give me a hint how to check if code is in design mode (so code can create empty instances),

You can handle all design time initialization in a DesignClass. You then use the DesignerAttribute to apply your design class to your control. Here is what mine looks like for my base EntityWeb Control


[
Designer(typeof(CompositeControlDesigner))
]
public abstract class WebEntityBase : WebControl, INamingContainer 

And this is my designer class...just



namespace BC.LLBLGen.Pro.GUISupportClasses
{

    public class CompositeControlDesigner : ControlDesigner 
    {
        public override string GetDesignTimeHtml() 
        {
            // Retrieve the controls to ensure they are created.
            ControlCollection controls = ((Control)Component).Controls;
            return base.GetDesignTimeHtml();
        }
        public override void Initialize(IComponent component) 
        {
            if (!(component is Control) &&
                !(component is INamingContainer)) 
            {
                throw new ArgumentException(
                    "Component must be a container control.", "component");
            }
            base.Initialize(component);
        }
    }
}


Otis wrote:

I'd be very happy and also how to debug this kind of code

  1. start VS and open project that contains the controls you want to debug
  2. Bring up the property pages for project. Select debugging, set debug mode to program ans set start application to devenv.exe
  3. Set breakpoints in code and start debugger
  4. In second instance of VS create a new project and add a refrence to the debug version of your 1st project.
  5. In second instance in your new project drag a control from the toolbox onto the page.

I go tthis from an ASP.Net server control book. Hope it helps

Bert

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 13-Nov-2004 14:37:55   

Thanks a lot Bert! I think I'll go with that designer idea, sounds great. I just have to figure out what exactly ControlDesigner.Initialize() does, but I think I'll find that out simple_smile

Also thanks for the debugger info. That will be of great help once I get all the interface code in the templates and the runtime libs. (which isn't that hard, basicly everything is already there).

John: I think I can overcome the limitation of GetCollection() and remove it entirely, as long as I can tell the EntityCollection code that it's in design mode. (but with Bert's example I think I can find a way).

IDataSource is a .NET 2.0 interface? I was carried away a bit about getting live data, because I thought: what if I can make adapter also a component and I can feed the colleciton with live data, but the grid doesn't ask for data in .NET 1.1 (at least not in vs.net, borland does it) so it will never be visible, (I think). Oh well, first things first simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 13-Nov-2004 22:50:04   

Ok findings so far (I'll quit now, the Leffe Blond beer is getting into my brain too much now wink )

(I did selfservicing today, which is harder than adapter, due to the lazy loading) - the error I got was caused by the lazy loading code which got executed and threw an exception, which resulted in the 'Specified method is not supported' error which is of no use to ANYONE on this planet but thanks to the debugging help Bert gave, I caught that one. - I implemented ICustomTypeDescriptor on EntityBase and EntityBase2. This solved the problem for webgrids where all kinds of properties show up in teh grids. This will be solved by this. - I implemented IListSource and IComponent on EntityCollectionBase. This went ok, but it caused an infinite loop - The loop was caused by the fact that Microsoft implemented incredible crappy code in vs.net for determining the IList's in a bound list: it calls ITypedList.GetItemProperties() a gazillion times and doesn't cache results, so it doesn't determine apparently if a collection is already seen. This causes problems with for example m:n relations which loop forever, or relations with self. After all kinds of caching mechanisms I gave up and implemented a path length if 1 as maximum (that's actually 2, but don't ask, it's ITypedList logic...)

This worked! I could drag a normal CustomerCollection on a form, bind it to a grid and when I clicked DataMember, I save 'Employees' Orders, Etc... and when I clicked open Employees I could select EmployeeEntity's collections as well simple_smile

It was very slow though (or this might be the debugger, don't know), so some sort of caching has to be implemented somewhere (took 1 second to get the list). The key is in DataViewManager, a class which is returned by DataSet.GetList() (the IListSource implementation of DataSet) and DataViewManager caches the property descriptors etc.

I now need to implement some sort of way to tell an entity to switch off lazy loading when in design mode (but that's not that hard simple_smile ) even if it's in a subcollection somewhere, and some more caching of property descriptors and IListSource lists to prevent loops.

Anyway, we're almost there, and it's even better than I'd hoped for. No extra object needed, just the entitycollections. After all the frustration with this, I can say, I'm very happy simple_smile

I too have the duplicate datasource item in DataSource. I don't know why that's done... Perhaps the IComponent itself and the IListSource.GetList() returned instance (which is the same), dunno.

Tomorrow I'll try to wrap this up and grab John's code to get adapter on track, which is IMHO easier to do, now I know this.

OK, as soon as some code + templates are runnable, I'll release them on the site for testing, which is pretty straight forward. The templates I change with Template Studio, so it's also a good testcase simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 14-Nov-2004 13:28:43   

Ok, I finetuned the selfservicing code, everything works now.

  • when in design mode, I remove every collection property from an entity that is on level 1. So if you drop a customercollection on the form, you can select Employees as datamember, as Employee is on level 1 (Customer.Employees) but you can't select subcollections of Employee, as that can cause loops which can't be stopped (and vs.net is not clever enough to filter them out).
  • I can't fix the duplicate datasource names. Dunno why these pop up, but frankly, I don't care, there is no side effect for that.
  • in ASP.NET no duplicate datasource names show up, but something strange happens there: you can't drop a collection on a form, it won't work, you need a control area on the form, very weird (this can be due to the fact that vs.net is not that great and an old dll was still in the cache or something, it now works ok...). Also DataMember lists are never requested. Perhaps this is because the .NET grid can't show hierarchies, I don't know, but it's weird. Anyway, it's not such a big deal.
  • in ASP.NET the infragistics webgrid can't work with the datasource apparently, at least doesn't read columns. Perhaps this is because the grid doesn't do this but I couldn't get it to work.

With this, I could create a master-detail form with customers and their orders with 2 grids on a form, some property selection, and 1 line of code (_customers.GetMulti(null); simple_smile ) and it worked. Needless to say: cool sunglasses simple_smile it at least saves some time when setting up the grids.

I'll now try adapter first, then go back to the typed lists/views. Adapter needs a little designer which retrieves all IEntityFactory implementations and enlists them in a list if the EntityFactory isn't set for the entitycollection object dropped on the form (a typed collection will have a factory, so the designer is then not shown). With the example of Bert this will be a piece of cake as it seems, but you'll never know. Anyway, I have high hopes we'll have design time support for both template groups by tomorrow. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 14-Nov-2004 15:02:38   

Ok adapter is very close! simple_smile

I made a designer, derived from ComponentDesigner which is bound to EntityCollectionBase2. At design time, you add the EntityCollection to the toolbox and you drag that one on the form. When initialized, it checks if the entityfactoryToUse is null, which is the case when you drag an EntityCollection on the form (but not when you use a typed collection) and it then reads all IEntityFactory2 types from the assembly and shows them in a window, you select one and from then on, the entitycollection will contain that type, so vs.net can retrieve the columns and the datamember list! sunglasses

One small bug to squash: m:n relations are readonly and vs.net tries to add a new entity, which is odd and doesn't work for m:n collections of course...

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 14-Nov-2004 16:58:16   

Ok, it all works!

I now have to add design time support to typed lists and typed views and I'm done. For now simple_smile . I've implemented everything directly into the entitycollection classes (base classes that is) so no extra class required.

There is one caveat with adapter, it serializes the EntityFactory into the form resource. I'm not sure how to do this properly, I guess using a DesignerSerializer class, but that seems to be a bit complex for now, I'll try tomorrow though.

Tomorrow (monday), after I've added typedlist/typedview design time support, I'll upload a testarchive to see if you all have complaints. This archive contains of new runtime libs and new sharedtemplates.

Here it works ok, but design time support is something that falls apart very fast... For now I want it to work, of course fancy designers can be added but that's for some other time, users now have to be able to create column definitions from the collections and bind textboxes to the current entity in that grid for example...

If all goes as planned, I'll merge the code into the main codebase and upload a final. simple_smile

John and Ray: I haven't been able to take a look at your code yet, but I'll do that tomorrow morning. simple_smile

Note Also added, is implementation of ICustomTypeDescriptor on EntityBase(2), so no more stupid columns in webgrids, these are all filtered out simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 15-Nov-2004 16:07:09   

OK!

Release candidate is live! You can all test the design time databinding support now, by going to the runtime libraries section and by selecting item 3 in the list, the design time databinding release candidate. Be sure to read the readme and the updated documentation on databinding.

Added: design time databinding support for entity collections, typed lists and typed views (Adapter & Selfservicing) Added: ICustomTypeDescriptor implementations on all entities to avoid unwanted columns in webgrids.

(EDIT) There is a build error in the VB.NET templates. Working on it (I forgot to run the build tests, my bad)

EDIT2: archive is updated.

Frans Bouma | Lead developer LLBLGen Pro
jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 16-Nov-2004 15:43:03   

Otis,

Nice work on the designer stuff, try this for me please, gen pubs, add an Entity Collection to your app, select Authors (don't believe it matters but its first), then drop a ms datagrid on your form, select authors as the datasource for the grid.

At this point it populates and all looks good, now click on the DisplayMember property for the grid, for me it locks up and infinite loops every time, My code that I gave you opens DisplayMember and shows X-None, not sure what is up there.

I haven't verified it but TypedList won't stick to the design surface, I believe this is because the generator allowed me to build a TypedList with no fields.

John

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 16-Nov-2004 16:47:55   

jtgooding wrote:

Nice work on the designer stuff, try this for me please, gen pubs, add an Entity Collection to your app, select Authors (don't believe it matters but its first), then drop a ms datagrid on your form, select authors as the datasource for the grid.

At this point it populates and all looks good, now click on the DisplayMember property for the grid, for me it locks up and infinite loops every time, My code that I gave you opens DisplayMember and shows X-None, not sure what is up there.

Hmm. The infinite loop was caused by m:n relations which are looping, but I filter these out in EntityCollectionBase... (i.e.: collections at level 1 are not reported as properties).

I'll try to reproduce it here.

I haven't verified it but TypedList won't stick to the design surface, I believe this is because the generator allowed me to build a TypedList with no fields. John

With typedlists/typedviews I didn't do a lot, all I did was making them visible in the designer by applying an attribute, as all interfaces/code is already implemented in DataTable. When no columns are in the typedlist, I think the DataTable doesn't do a good job, but I tested this with a typedlist with columns and everything worked fine.

I'll check out that pubs error...

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 16-Nov-2004 17:02:49   

It works here like a charm.

However I think I know what's wrong: be sure to reference the new ormsupportclasses in all your projects, also in the winforms project and recompile that project BEFORE you drag the entitycollection on the form. Otherwise it will use the old ormsupportclasses dll in the bin folder. At least that's what happened here: I forgot to reference the ormsupport classes in the winforms project, dragged the collection on the form and it bragged that EntityCollection didn't implement ICOmponent... Once I fixed the reference, compiled, then tried again, it worked.

Could you verify if that works at your side as well?

Frans Bouma | Lead developer LLBLGen Pro
Jelle
User
Posts: 17
Joined: 25-Aug-2004
# Posted on: 18-Nov-2004 17:05:41   

Works nicely here, except when i run my sample app, it shows the factory chooser...

Anyway, any thoughts about making normal entities also bindable ? Or is this something impossibles in .net 1.1 ?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39826
Joined: 17-Aug-2003
# Posted on: 18-Nov-2004 17:23:42   

Jelle wrote:

Works nicely here, except when i run my sample app, it shows the factory chooser...

In adapter, this is required, as the EntityCollection is a generic class, so you have to specify which entities you'll put into the collection so the columns are known simple_smile

Anyway, any thoughts about making normal entities also bindable ? Or is this something impossibles in .net 1.1 ?

You mean, dragging an entity onto a form? As they're not lists, there is little you can do with them as it seems, do you have an example in mind?

Frans Bouma | Lead developer LLBLGen Pro
1  /  2