Generic Browse Dialog


Author
Message
Greg McGuffey
Greg McGuffey
Strategic Support Team Member (3.3K reputation)
Group: Forum Members
Posts: 2K, Visits: 6.6K
My pleasure. Let me know if you need more clarification or if you come upon another solution. Always good to learn/discover different ways of solving a problem and/or understanding all the nuances of a problem!
Ger Cannoll
Ger Cannoll
Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)
Group: StrataFrame Users
Posts: 430, Visits: 507
Hi Greg. Am working my way through a sample for a generic browse. Just a few questions at this stage (prompted after looking at your example)

How do I instantiate a BO in C#

Does this work:

BusinessLayer bo = new BusinessLayer();
bo.Parent = "XYZ" etc

On your sample, I have seen references to :

BusinessLayer bo = new BusinessLayer();
bo=CType(Activator.CreateInstance............)

Just not sure if I have to use CType, and if I have to use it, what is it doing ?

 

Greg McGuffey
Greg McGuffey
Strategic Support Team Member (3.3K reputation)
Group: Forum Members
Posts: 2K, Visits: 6.6K
How do I instantiate a BO in C#


The first thing to be clear on is what you want to work with when using or creating an object. I.e. if I have a BO that inherits from the _BaseBO in the project, which in turn inherits from the SF BusinessLayer (etc.), I can work with it as the actual typed BO from my project (like CustomersBO) or as a _BaseBO or as a BusinessLayer. E.g. all of the following are valid ways to create a CustomersBO using Activator.CreateInstance:



Type boType = Common.GetTypeFromReferencedAssemblies(boTypeName);

CustomersBO custBO = (CustomersBO)Activator.CreateInstance(boType);

_BaseBO custAsBaseBO = (_BaseBO)Activator.CreateInstance(boType);

BusinessLayer custAsBusinessLayerBO = (BusinessLayer)Activator.CreateInstance(boType);




Note that Activator.CreateInstance takes a Type and then creates an object of that type, but it returns an Object. The actual type is of the specific type you create, CustomersBO in this example. I.e. in all instances in this example, the actual object returned by CreateInstance is a CustomersBO. We are just casting to a type we want to work with. As long as the object supports the cast, we're good.



In the case of this sample app, I left it as _BaseBO because in Ivan's original sample he was using the GetFieldValueByPrimaryKey method (I ended up not using this, so the _LookupBusinessObject could be changed to by of type BusinessLayer rather than _BaseBO).



Note that this sort of thing isn't of much use:



BusinessLayer bo = new BusinessLayer();

bo=CType(Activator.CreateInstance............);




The BusinessLayer object created on the first line is just created, then gets dereferenced on the next line, and thus setup for garbage collection. Either use something like I was using above or something like this:



BusinessLayer bo = null;

bo=CType(Activator.CreateInstance............);




Setting to null is not strictly necessary, but the VS compiler barks if you don't do it.



Is this starting to make more sense?



Ger Cannoll
Ger Cannoll
Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)
Group: StrataFrame Users
Posts: 430, Visits: 507
Hi Greg.

I am obviously missing something fairly basic here .

For instance , if I want to create a new "table" object, all I do is:

DataTable dt = new DataTable();

and than I can use all the properties and methods of dt

Why can I not do the same for BusinessObjects

i.e.

BusinessLayer bo = new BusinessLayer();


Greg McGuffey
Greg McGuffey
Strategic Support Team Member (3.3K reputation)
Group: Forum Members
Posts: 2K, Visits: 6.6K
First, you can do that, but in the context of this example, it doesn't get us what we want (a general solution to the lookup problem). The way the BOs work is using inheritance. I.e. the final functionality of the BO is the combination of all the classes that it inherits from plus the functionality it adds. So, if you look at the CustomersBO in object browser you'll see that is composed of (starting at the bottom, working up):



- Object: base .NET object

- MarshalByValueComponent: Provides basic component functionality, allows BOs to be used in remoting situations

- BusinessLayerBase: Provides basic BO functionality, manages bound controls, provides CopyDataFrom functionality

- BusinessLayer: Provides base BO functionality, broken rules, events, base fill methods etc.

- _BaseBO: Add the GetFieldValueByPrimaryKey method, used in Ivan's original sample

- CustomersBO: Adds meta data (table name, field info) that actually allows access to the customers table



There are two important points here:

1. You can treat the CustomersBO as any of the objects it inherits from by casting it.

2. If you want to actually access data, you need a full blow BO (that has been created by the BO Mapper). The BusinessLayer doesn't have enough functionality/meta data yet.



In the context of this sample, what we are doing is writing code that does not know the exact type of BO that will be used (e.g. it can be used with CustomersBO or OrdersBO or WidgetsBO). This requires two approaches. First we must use the Activator.CreateInstance() to create the BO. This uses reflection to create a specific type of BO, as configured via the BrowseDialog. This allows that specific BO to be used to access data from the search, without knowing what the properties are in the LookupControl. In order to interact with the BO, we need to figure out what functionality we need and then cast to the necessary object form within the BO's inheritance hierarchy. I.e. in this design, we cast the BOs to _BaseBO (though we don't actually need that functionality, just the BusinessLayer's functionality). This means that while within the LookupControl we are dealing with the _LookupBusinessObject, that is a _BaseBO the actual objects are of specific types of BOs. In the sample, it is a CustomersBO. But it could be an OrdersBO, etc.



When you know what the object is at design time, then you use the direct instantiation methods you are talking about ( CustomersBO bo = new CustomersBO; ). However, when you are programming a component/control/class that will not know the exact type it is working with until runtime, you have to use something like this. In those cases, you either pass in the exact object, which is then referenced as the necessary object type (or interface type) within the code, or you have to use reflection to create the object based on a fully qualified class name, using Activator.CreateInstance(), then cast it to the desired type.



Is this starting to make sense? Answering the right question?



Ger Cannoll
Ger Cannoll
Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)
Group: StrataFrame Users
Posts: 430, Visits: 507
Hi Greg.. Did'nt realise there was so much in Reflection so I am taking it fairly slowly now. I have just set up a button with a few liines of code. Its compliling ok but am getting a run time error:

 

1  string boString;
2  boString = "Kernel_BOLibrary.SmaBO"; // This is the name of one of my Business Objects
3  MicroFour.StrataFrame.Business.BusinessLayer bo = new MicroFour.StrataFrame.Business.BusinessLayer();
4  Type oType = Type.GetType(boString,true);
5  // bo = Activator.CreateInstance(oType);

Could not load type 'Kernel_BOLibrary.SmaBO' from assembly 'Kernel_App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Runtime error on on Line 4.(All my Business objects are in the project in a DLL called Kernel_BOLibrary.DLL Wink I tried it without the Kernel_BOLibrary and it came up with a similar message.  

Also tried to input Type.GetTypeFromReferencedAssemblies but intellisense would not bring this up 


Greg McGuffey
Greg McGuffey
Strategic Support Team Member (3.3K reputation)
Group: Forum Members
Posts: 2K, Visits: 6.6K
Gerard,



This is actually a good way to start understanding reflection, which can be a very powerful tool.



OK, now to your issues:



- Just to be sure, you do have the Kernel_BOLibrary assembly referenced in project where this code is executing right? If not, that could cause the problem.

- You need the fully qualified type name (which you may have, I'm just double checking here). When using a string like this, the easiest way to get this done is to use the Object Browser. Simply navigate to the BO, right click on the BO and click Copy. Then paste this into your code. It will be the fully qualified type name.

- To use the Common.GetTypeFromReferencedAssemblies() method, you still need the fully qualified type name and you need to make sure the assembly containing the code includes a reference to the MicroFour StrataFrame Base.dll and you have a using statement for MicroFour.StrataFrame.Tools namespace (or use the fully qualified method: MicroFour.StrataFrame.Tools.Common.GetTypeFromReferencedAssemblies()).

- You really, really don't need to set the BO to an instance of a new BusinessLayer object. The intent of the declaration is to identify the type of the variable that you'll use. The actual instance will use a type determined at runtime. So you'd replace this:

3 MicroFour.StrataFrame.Business.BusinessLayer bo = new MicroFour.StrataFrame.Business.BusinessLayer();


with

3 MicroFour.StrataFrame.Business.BusinessLayer bo = null;


or you could replace lines 3 and 5 with a single that declares and then sets the bo variable. Using the this concept to set the BO and and the BO name string along with the GetTypeFromReferencedAssemblies you might reduce your code to:

1 string boString = "Kernel_BOLibrary.SmaBO"; // This is the name of one of my Business Objects

2 Type oType = MicroFour.StrataFrame.Tools.Common.GetTypeFromReferencedAssemblies(boString);

3 MicroFour.StrataFrame.Business.BusinessLayer bo = Activator.CreateInstance(oType);




Give this a try and see how it goes. We'll go from there....
Ger Cannoll
Ger Cannoll
Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)
Group: StrataFrame Users
Posts: 430, Visits: 507

I have Kernel_BOLibrary referenced as I can access the Business Objects no problem on other butons on the form (not using reflection)

Ok. Still bogged down I'm afraid at this Gettype command. I am not sure at this stage what parameters this takes.I've tried a few permutations with various run time errors

boString = "Kernel_BOLibrary.SmaBO";   // (Got by rt clicking the Business Object in Object Browser)
Error--->Could not load type 'Kernel_BOLibrary.SmaBO' from assembly 'Kernel_App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'......indicates

boString = "SmaBO,Kernel_BOLibrary";    // Tried a comma between BO and the BO Library
Error --->Could not load type 'SmaBO' from assembly 'Kernel_BOLibrary'.

 (looks like its closest to being correct as it seems to recognise the BO and the BOLibrary ??)

Greg McGuffey
Greg McGuffey
Strategic Support Team Member (3.3K reputation)
Group: Forum Members
Posts: 2K, Visits: 6.6K
There has got to be some issue with references/bo names. In cases like this, I'd suggest creating a sample app focused on this problem. Start with a solution with a single project. Put a BO in it and see if you can get it work. Then try adding a second project and a BO in it, see if it works. The main form would just have some code in the load event handler that you've been working on: set boString, boType and try to create an instance using CreateInstance. Post the solution that doesn't work with a stack trace. Oh, and make BOs that point the StrataFrameSample database (like to the Customers table) so I can test it out quickly.
Ger Cannoll
Ger Cannoll
Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)Advanced StrataFrame User (630 reputation)
Group: StrataFrame Users
Posts: 430, Visits: 507
Ok Greg.... will give that a try .
GO

Merge Selected

Merge into selected topic...



Merge into merge target...



Merge into a specific topic ID...




Similar Topics

Reading This Topic

Login

Explore
Messages
Mentions
Search