Reusable Smart Parts?

Topics: CAB & Smart Client Software Factory
Mar 9, 2007 at 10:10 PM
What are the best practices for creating reusable Smart Parts in CAB? For example, I would like to create a Smart Part that consists of view that lists the employees for a given store and allows one to be selected (ie a list box) and a presenter that accesses a SCSF Service Proxy to retrieve the list of employees and do some other "business logic". This control is then used throughout the application. I would like to be able add this Smart Part to the Visual Studio toolbox and then simply drag and drop it onto other Smart Parts.

If I create my Smart Part as per normal and then drop it onto a another Smart Part, it doesn't work, because the Visual Studio Designer generates code like the following:

this.associateListBox1 = new BestBuy.CM.Core.AssociateListBox();

This code doesn't invoke Object Builder to do it's thing, so the Smart Part is never constructed correctly and thus exceptions are tossed at design time and run time.

So how do I get Smart Parts to play nicely with the Visual Studio Designer?

Should I not create a Smart Part in the first place? If so, how do I use Object Builder to implement the dependency between the view/presenter and the service?

Mar 10, 2007 at 2:40 PM
SmartParts are composed on runtime because you add them to the workitem and then to a specific workspace.

   AssociateListBox lb = WorkItem.SmartParts.AddNew<AssociateListBox>();
   WorkItem.Workspaces["SomeWorkspace"].Show(lb);
Your smartparts can have nested workspaces as well.

Let me know if this helps.

Thanks,
http://staff.southworks.net/blogs/matiaswoloski
Mar 12, 2007 at 3:41 PM
Edited Mar 12, 2007 at 3:43 PM
I had that same issue Quad.
What i did was use the smartpartplaceholders in my views. You drop one on like a panel and fill the "SmartpartName" with it's name. Like "CustomerDetails" I use constants in the views initialize section.
spphCustomerDetails.SmartpartName = Constants.SmartPartNames.CUSTOMER_DETAILS;
Then when i create the smartpart with the namea and load my view into a workspace that uses the smartpart.
Workitem.Smaprtparts.AddNew<CustomerDetailsSmartpart>(Constants.SmartpartNames.CUSTOMER_DETAILS;
MyView myViewWithSmartPart = workitem.addnew<MyView>("SomeID");
 
IWorkspace workspace = Workitem.Workspaces["MyWorkspace"];
workspace.show(myViewSmartPart);
Well that is what i do, I found trying to do it in designer never worked if it had a presenter since, like you found out, the object builder doesn't build the part.

Hope this helps ya,
Jordon
Mar 12, 2007 at 6:34 PM
Edited Mar 12, 2007 at 6:36 PM
Matiaswoloski, I know how to add views programatically, but what I am having troubles with is adding views at design time.

As it turns out, one of my assumptions was wrong. I thought that Object Builder would not be able to do its job, but it does. It must walk the object reference tree of an object at creation time and look for Object Builder attributes on downstream classes. Here's what I did that works.

- Created a business module called CommonViews with the Smart Client Factory recipe.
- Created a view and presenter called AssociateComboBox.
- Changed AssociateComobox to inherit from System.Windows.Forms.ComboBox and removed the function OnLoad.
- Added a injection constructor to AssociateComboBoxPresenter that has a service dependency.
- Compiled CommonViews.

In another business module:

- Added a reference to CommonViews.
- Added the controls in CommonViews to the Visual Studio toolbox.
- Dragged and dropped AssociateComboBox onto an existing view (SandboxView) in the Visual Studio designer.

Viola!

When the SandboxView is added to the work item, Object Builder automagically calls AssociateComboBox.Presenter.set and also calls the Injection Constructor on AssociateComboBoxPresenter.
Mar 15, 2007 at 6:02 PM
I ran into one little glitch. The Visual Studio designer sets the ID property of the control to the same value as you name it. If you name two controls the same name (very likely), CAB will toss an exception saying you can't have two views with the same ID. Therefore, I was forced to change one of the IDs to make it unique.
Aug 14, 2007 at 12:04 PM
If you make some calls for _pressenter, in OnLoad function, then the control will crash in design time. if not, then it's ok. And I don't think you'll need an full functional control in design time (with presenter and required services).
To solve _presenter's call do this :

if( _resenter != null ) _presenter.InitPresenter();

And that's all