Ask a questionAsk a question
 

QuestionMarkupExtension to Connect WPF to CAB Serviecs

  • Wednesday, July 12, 2006 2:33 PMJared Bienz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    We are working on a project that integrates WPF and the CAB (Composite UI Application Block). One thing we would really like to do is connect CAB services to our views using markup. A prime example of why we'd like to do this is in data binding. Consider the following:

    xmlns:xt="clr-namespace:FxBindSource.MarkupExtensions"
    xmlns:sv="clr-namespace:FxBindSource.Services"

    < ObjectDataProvider  x:Key="UserCollectionDS"  d:IsDataSource="True"  ObjectInstance="{xt:Service sv:IUserProvider}"  MethodName="GetUsers" />

    The idea is simple: create ServiceExtension which inherits from MarkupExtension and have ServiceExtension look for the specified interface in the containing WorkItem’s  Services collection.

    The implementation of ServiceExtension, however, has proven to be much more difficult then we thought. The main reason were struggling is it seems we have no way to add services to the IServiceProvider passed into the ProvideValue method of the MarkupExtension.

    All of our views inherit from a BaseView class which exposes the current WorkItem. So, we used the IServiceProvider to get the IProvideValueTarget service and finally the actual target object where the extension is being used. We thought we would cast the target to a FrameworkElement and walk the parent chain until we came to our base view. Unfortunately we realized quickly that not everything inherits FrameworkElement (particularly ObjectDataProvider).

    Next, we noticed that we could get a ParserContext from the IServiceProvider and the debugger showed us that ParserContext has a property for the RootElement.  RootElement  always seems to be our view, but again we quickly realized that the RootElement property is not publicly exposed.

    What we would really like to do is be able to add services to the ParserContext  that’s used while the object is being built-up. If this is not possible, we would like to have better access to the visual tree when the MarkupExtension is providing its value.

    Are we missing anything? Does this sound beneficial or is there another way to accomplish what we’re working on?

    Thanks,

    Jared Bienz

    SolerSoft

All Replies

  • Wednesday, August 30, 2006 11:18 PMRob RelyeaModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Sorry for the delay.

    How are you currently getting the ParserContext from within the ServiceExtension code?

  • Thursday, September 14, 2006 10:17 PMJared Bienz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Sorry, I haven't been around in a while.

    I was trying to remember how I got to the ParserContext, but I realized that perhaps I never obtained it in code.

    While debugging I realized that the IServiceProvider is actually a ProvideValueServiceProvider. Using Lutz Roeders famous tool, I was able to determine that the ParserContext was passed into the ProvideValueServiceProvider constructor and that it was stored in the _context field. However, looking at the GetService method, the only services that could possibly be obtained are IProvideValueTarget, IXamlTypeResolver, IUriContext and IBamlReader.

    This is quite restrictive, especially since we cannot register services to become available to the extensions.

    My work-around was to add a static IServiceProvider property to my ServiceMarkupExtension. When my application loads, I override the AddServices method (standard CAB stuff). In AddServices I have access to the Root WorkItem. At this time I can connect the Root WorkItem with the static IServiceProvider property on the ServiceMarkupExtension.

    When it's time for the extension to obtain a service, it first tries to see if the target provided by IProvideValueTarget implements IServiceProvider. If it does, the extension will try to obtain the service directly from there. If not, it will see if the target is a FrameworkElement. From there, it will walk the visual tree looking for any element that implements IServiceProvider. If the target is not a FrameworkElement, or if no IServiceProvider was found anywhere in the visual tree, the service extension will fall back to the IServiceProvider specified in the static property. This, of course, is the Root WorkItem.

    Unfortunately, this means that services bound to non FrameworkElments (like ObjectDataSouce) must be registered in the Root WorkItem rather then a WorkItem closer to the view. But for now, that’s the best I could come up with.

  • Thursday, February 14, 2008 3:50 AMBenK3 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

     

    Has anyone found a better way of doing this?  Or also how do you call a CAB service from a WPF validator  here you have no UI hook at all.

     

    Regards,

     

    Ben