UIExtensionSites usablility

Topics: CAB & Smart Client Software Factory
Feb 17, 2006 at 2:24 PM
originally posted by: AndrePiwoni

Another shortcoming of UIExtensionSites is that during module load time it is's not possible to add to UIExtensionSite. There is no reference to any WorkItem instance at that point other than to WorkItems instantiated during load time. One may argue that module's WorkItem.OnRunStarted can make this contribution but I may want to add to the menu item that would trigger creation of a WorkItem.

Any thoughts, experiences with UIExtensionSite!?
Feb 17, 2006 at 3:37 PM
originally posted by: sklett

What if you add this in your ModuleInit class:

<code>
private WorkItem _rootWorkItem;

InjectionConstructor
public Module(ServiceDependency WorkItem rootWorkItem)
{
_rootWorkItem = rootWorkItem;
}
</code>
Feb 23, 2006 at 2:25 PM
originally posted by: AndrePiwoni

As I started to work on UIExtensionSite for NavBarControl from DevExpress I realized that UIExtensionSites are not as helpful as I initially thought they would be.
BankShellApplication does a lot of work to create ToolStripItems for menus. These ToolStripItems are added to UIExtensionSite via UIElementAdapters provided by CAB framework, but UIElementAdapters don't do much work. Comment in UIElementBuilder which creates ToolStripItems implies that this logic will be moved into the framework. I consider it a good thing. Why every module has to create ToolStripItem on its own.
Having said that, I have been thinking about another use of UIElementAdapterFactories. Instead of doing the following:

WorkItem.UIExtensionSites"NavigatorBar".Add(new NavBarGroup());

I'd like to say:

WorkItem.UIExtensionSites"NavigatorBar".Add(new CustomerCategory());
WorkItem.UIExtensionSites"NavigatorBar".Add(new OrderCategory());

where OrderCategory and CustomerCategory don't have common interface, in fact, these could be any objects from different modules.

Few steps are needed in UIExtensionSite.Add(object o) method to make it happen.
(1)Factory for UI control type of NavBarControl corresponding to this UIExtensionSite has to be located.
(2)This factory, in turn, has to locate IUIElementAdapterFactory capable of converting CustomerCategory and OrderCategory to NavBarGroup control which can be added to NavBarControl.
(3) UIElementAdapterFactoryCatalog has to be smarter in the following way:

Insted of having

private List<IUIElementAdapterFactory> factories;

it may have:

private Dictionary<ControlType,Dictionary<ObjectType, IUIElementAdapterFactory> factories;

Then UIExtensionSite instead of just using one IUIElementAdapter it could use UIElementAdapterFactoryCatalog to look up capable IUIElementAdapter to accomplish this task. This approach allows converters to be more reusable, but it doesn't solve yet placement of child controls within parent control.

So far, in my opinion, UIExtensionSites are weakest link in CAB (and Commands). Let's make it better by providing feedback.

Andre
Feb 28, 2006 at 1:22 PM
originally posted by: AndrePiwoni

Thank you for your response.

So technically, it is possible for this simple case. But what if I'd like to add to extension site in another work item!? Again, technically I could add WorkItems to RootWorkItem or create all UI extensions in RootWorkItem but it's not a good solution. Too contraining!

I'd like to restate what I have said earlier as a requirement. Here we go:

Have module A to make contribution to UI control, which is defined and contributed to application UI in module B, where module B and not module A is in control of adding such contribution to application UI. Module A does not necessarily know about module B and vice versa (ideally!).

Example 1:

Module A wants to contribute to a menu at the following path: Menu/Adminitration/Locations/MyOffice. It does not know anything about module B.

Example 2:

Module A wants to contribute navigation group to a navigation bar at the following path:
NavigationBar/Administration/Locations/MyOffice. Again, it does not know anything about module B. In addition, this navigation group may contain just items or custom control (that is why I wanted adapter for converting any object to UI control).

Please, share your experiences and thoughts!
Mar 8, 2006 at 9:18 AM
originally posted by: AndrePiwoni

Here's another consideration:

CAB examples and labs that I have deal with adding UI extensions to one navigation structure, such as menu bar, tree view

(Hands On Lab - 07 Advanced CAB) or tool bar.

Let's say I want to contribute item to UI such that it would show up at the same time on menu bar, navigation bar, tree view

and toolbar. It is not convenient to have the following done on your own for every contribution:

<shellitems>
<menuitems>
<add site="MenuBar" label="Administration" register="true" registrationsite="MenuBar/Administration" />
<add site="NavigationBar" label="Administration" register="true" registrationsite="NavigationBar/Administration" />
<add site="TreeView" label="Administration" register="true" registrationsite="TreeView/Administration" />
<add site="ToolBar" label="Administration" register="true" registrationsite="ToolBar/Administration" />
....
</menuitems>
</shellitems>

and then

WorkItem.UIExtensionSites"MenuBar".Add(menuItem);
WorkItem.UIExtensionSites.RegisterSite("MenuBar/Administration",menuItem);
WorkItem.UIExtensionSites"NavigationBar".Add(navigationGroup);
WorkItem.UIExtensionSites.RegisterSite("NavigationBar/Administration",navigationGroup);
WorkItem.UIExtensionSites"TreeView".Add(treeNode);
WorkItem.UIExtensionSites.RegisterSite("TreeView/Administration",treeNode);
WorkItem.UIExtensionSites"ToolBar".Add(menuItem);
WorkItem.UIExtensionSites.RegisterSite("ToolBar/Administration",menuItem);

It is a headache. Since these four sites cannot be registered under "Administration" name, their name has to be qualified, unless they are named differently.

Here's one possible solution:

<shellitems>
<menuitems>
<add site="uie://NavigationStructures" label="Administration" register="true" registrationsite="Administration" />
....
</menuitems>
</shellitems>


CAB framework could internally add this site to all known NavigationStructures as shown earlier. 3rd party could add another NavigationStructure like some popup menu etc.

To make it short, what I'm asking for is a functionality similar to that provided by Actions in Java, Eclipse and other frameworks.
Mar 8, 2006 at 10:39 AM
originally posted by: JaredBienz

I agree with all of this here, especially about modules having to know the actual control type.

For example, what if I start with System.Windows.Forms.MenuItem today and then three months from now I want to switch to using Infragistics menu bars instead. As far as I can tell, each module would have to be touched. apiwonis suggestion of an object-to-UI adapter would certainly help here, but still a new adapter for each class would have to be written to support the new menu bar.

What would be even better is if our company could specify our own Company.MenuItem class and then somehow map that instance in the background to a true WinForms.MenuItem or Infragistics.MenuItem instance. All modules for our application would use our Company.MenuItem class and if we change the back-end, the modules don't have to be touched.
Mar 8, 2006 at 10:44 AM
originally posted by: JaredBienz

I want to note that my suggestion doesn't negate apiwonis object mapper. I think the two could be used together if desired, or the module can manage the menu items directly. The abstraction of the true control simply helps isolate the module, regardless of how the menuitem is created.
Mar 8, 2006 at 2:57 PM
originally posted by: AndrePiwoni

Jared,

Having object-to-UI adapter for every UI representation(menuItem, navItem,treeNode) of a single object was my concern since I started to think about. Since each of these UI representations requires similar info like description, icons etc. we could end up with only one adapter per UI representation by having UIElementInfoFactory that would allow objects to register its description, icons etc.
Then in Add(object obj) method adapter for menu item would ask factory for UI information for object passed as an argument.

Here's a link to article describing such approach:
http://jdj.sys-con.com/author/herold.htm

So if module contributes to extension site in a very abstract way then AdapterFactory could pick-up Adapter for UI control type used in extension site, like Infragistics, and convert abstract representation to UI control. This abstract representation could be WorkItem which registers its description, icons etc. with UIElementInfoFactory, which, in turn would be used by Infragistics adapter to create actual UI control. Another possiblilty is declaring action that would contain such information like description and icons.

In terms of CAB, when I think about work items they often represent handlers to actions trigerred by UI navigation controls. It may not be a good idea to create work item for UI control handler right away because care must be taken about a cost of construction. That is why actions, like those in eclipse, declaratively could provide UI info and receiver type(workItem).

Andre
Mar 10, 2006 at 10:03 PM
originally posted by: rj45

Good Discussion. Glad I'm not the only one dealing with this. The goal of creating a reusable shell means that different implementations would require different tool-sets.

I am currently handling the control-set independence problem by using the "Company.MenuItem" method described by Jared above. The problem is, I can really only implement the most common tools, since WinForms ToolStrips don't have a drop-down font picker tool like Infragistics has (for example).

Right now, I'm just handling this through a service that recieves the generic tool definitions and turns them into the appropriate tools. Like I said, it's working, but I can only use tools that translate well between control-sets. I just write a service instance for each tool set and then change the version that gets loaded depending on which control-set I want to use. Essentially, I'm just hiding the UIExtensionSites from my module developers and making them go through my service to add UIElements through generic tool definitions.

Another problem when dealing with tool-set independence is working with command invokers. Since WinForms ToolStripItems use the "Click" event and Infragistics ToolBase items uses the "ToolClick" event, whatever the solution, it has to accomodate for the various event naming conventions of individual tool-sets.

I like Andre's suggestion of a "UIElementInfoFactory", but the definition of the "UIElementInfo" would have to be very dynamic, otherwise we're right back to the problem of only being able to use the tools that were common among the various tool-sets.

Cheers,

-Ryan