AppDomain Isolated WPF Add-Ins [Jesse Kaplan]


Earlier Jack announced an exciting new feature in our beta2 release in the ability host WPF controls across AppDomain boundaries. This will allow add-ins to generate their own UI and to pass it back for display within the hosts window. Ever since the add-in model was concieved this has been near the top of our list for feature requests and I want to thank the WPF team for scrambling to get this work done in time for the 3.5 release.


With that in mind I’d like to finally update our calculator samples to be just a bit more interesting. The attached sample requires Orcas Beta 2 and demonstrates a fairly typical add-in scenario in which an AppDomain isolated add-in generates some UI at the request of the host and the host displays directly as part of the application. If you take a look at the screenshot below the lower-right hand corner of the application is the piece that the add-in is generating. Everything else is generated by the host either on its own or using data from its various add-ins. In this sample only one section of the host actually displays the add-ins content but there is nothing limiting that in the product: a host can display multiple FrameworkElements from one or more add-ins anywhere it wishes. 


Calculator Screen Shot


When you download the application you should play around with the “Graphing Calculator” add-in. It really shows how smooth the integration between the AppDomains are in that the add-in doesn’t need to mearly display a static image but can accept rich interaction directly from the user even when hosted cross domain.


We’ll go into more depth later about this technology, some of the scenarios it enables, and some of the gotcha’s you might run into, but for now I’d like to just get the sample into your hands and give you a brief taste of how easy it is to integrate this into your add-in application by comparing the differences between the pipelines of the old calculator and the new graphical add-ins.


First let’s take a look at the views:


Numerical Calculator:


    [AddInBase]
    public abstract class Calculator
    {
        public abstract String Name
        {
            get;
        }
        public abstract IList<Operation> Operations
        {
            get;
        }
       public abstract double Operate(Operation op, double[] operands);
    } 


Graphic Calculator:


    [AddInBase]
    public abstract class VisualCalculator
    {
        public abstract String Name
        {
            get;
        }
        public abstract IList<Operation> Operations
        {
            get;
        }
        public abstract UIElement Operate(Operation op, double[] operands);
    }


Only one line has changed, instead of returning a double the view simply returns the basic WPF control UIElement. The changes to the host view are just as simple.


Now let’s look at the adapters as this is where the real magic happens. This time we’ll just compare the pieces of code that have changed.


 On the add-in side:


        public double Operate(Calculator.Contracts.IOperationContract op, double[] operands)
        {
           return _view.Operate(OperationViewToContractAddInAdapter.ContractToViewAdapter(op), operands);
        }


        public INativeHandleContract Operate(Calculator.Contracts.IOperationContract op, double[] operands)
        {
            return VisualAdapters.ViewToContractAdapter(_view.Operate(OperationViewToContractAddInAdapter.ContractToViewAdapter(op), operands));
        }


The only changes here is that instead of passing back the result directly across the boundary as a double we now pass it back across as an INativeHandleContract and use the new class VisualAdapters to convert from the UIElement the add-in passes back into the INativeHandleContract that gets passed across the boundary. System.AddIn.Pipeline.VisualAdapters is a new class in the new System.Windows.Presentation assembly that contains the core functionality that enables the cross-appdomain hosting; you’ll see it’s use again in the host side adapters to convert from the INativeHandleContract back into a WPF control.


        public override double Operate(HostView.Operation op, double[] operands)
        {
            return _contract.Operate(OperationHostAdapters.ViewToContractAdapter(op), operands);
        } 


        public override UIElement Operate(HostView.Operation op, double[] operands)
        {
            return VisualAdapters.ContractToViewAdapter(_contract.Operate(OperationHostAdapters.ViewToContractAdapter(op), operands));
        } 


Again, the only changes required were to change the return value to UIElement and to use our new helper class to convert from the contract back into a a new UIElement. This method actually returns an object of type FrameworkElement that lives in the hosts AppDomain and can be manipulated and plugged into the visual tree as any local FrameworkElement can.


That should be enough to get everyone started, as I said we’ll be following up with more info and samples in the weeks to come. If you have any questions about this new capability please just let us know.


 


Note: The attached sample was built for a pre-RTM version of .NetFX 3.5 and will not work on the RTM build. For an updated sample please see our codeplex site here: https://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=clraddins&ReleaseId=9454


 

AppDomain Isolated WPF Demo.zip

Comments (35)

  1. ppavan says:

    I have developed some AddIns where I need to pass VisualBrush and Storyboards back to the Host. How can I do that in a clean way. Right now I have to use hacks to get it done…as in passing a dummy Border with its background set to the VisualBrush and its Resources containing the Storyboards. I would prefer a cleaner way of doing this.

    Any suggestions?

    Thanks for the great work you guys are doing!

    Pavan

  2. Garry Trinder says:

    For questions about specific WPF controls and the add-in model please post questions on this forum:

    http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=119&SiteID=1

    The WPF team monitors that closely and there are developers there familiar with WPF and the add-in model support who can help you.

    Thanks,

    Jesse

  3. Hi,

    The attached sample does not run “out of the box” in visual studio 2008 beta 2.

    Assembly references is missing, and no addins are found when run (after adding the required references).

    Regards,

    Lars Wilhelmsen

  4. Garry Trinder says:

    Sorry you’re running into problems here. We tested this on a few machines before posting and have had at least a few people contact us through the blog who didn’t run into problems, but it sounds like there may be a configuration out there that is still causing problems.

    Just to clear a few things up. Is this a clean install of beta2 or were previous builds of 2008 installed on the machine? Which assembly reference did you need to add?

    Finally, can you list out any warnings you get during discovery? You need to make the following change to the application to get these warnings:

    In CalculatorHost.xaml.cs change the line that says

       AddInStore.Rebuild(path);

    to

       String[] warnings = AddInStore.Rebuild(path);

    Then put a break point after that and take a look at the warnings array.

    Thanks,

    Jesse

  5. Alex Hoffman says:

    OT, but is there an MSDN forum for Add-Ins?

  6. Garry Trinder says:

    There is no dedicated forum for the add-in model but we are instead part of the base class library forums.

    You can find that forum here: http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=39&SiteID=1

    –Jesse

  7. A somewhat awkward but necessary first step… I am a Software Development Engineer on the WPF Application

  8. jabbera says:

    I tried to use the email link, but your email link is out of date.

    I am trying to write an add-in that hosts a frame in it. When a certain event occurs I want to update the frame source to point to a new web page. When I do I get:

    A first chance exception of type ‘System.Deployment.Application.InvalidDeploymentException’ occurred in System.Deployment.dll

    Additional information: Application identity is not set.

    Then my frame disappers.

    I have modified the calculator demo to show the problem.

    Change: private System.Windows.UIElement Graph(double[] operands) as below.

    Run. Click Push Next 5 time. Click Graph. Click Push Next 5 more times. Click Graph. Get error.

    Code:

           Frame f;

           private System.Windows.UIElement Graph(double[] operands)

           {

               if (f == null)

               {

                   f = new Frame();

                   f.Source = new Uri("http://blogs.msdn.com&quot;);

                   f.Width = 200;

                   f.Height = 200;

               }

               else

               {

                   f.Source = new Uri("http://www.microsoft.com&quot;);

               }

               return f;

           }

  9. Marcel van Laar says:

    Hi,

    First, this is a great example!

    I’m trying to activate the add-in’s in a new AddInProcess, but when I try to activate the ‘Graphic Calculator’ I get an TargetInvocationException telling me the following:

    System.Reflection.TargetInvocationException occurred

     Message="Exception has been thrown by the target of an invocation."

     Source="mscorlib"

     StackTrace:

       Server stack trace:

          at System.RuntimeMethodHandle._InvokeConstructor(Object[] args, SignatureStruct& signature, IntPtr declaringType)

          at System.RuntimeMethodHandle.InvokeConstructor(Object[] args, SignatureStruct signature, RuntimeTypeHandle declaringType)

          at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

          at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)

          at System.AddIn.Hosting.ActivationWorker.Activate()

          at System.AddIn.Hosting.AddInServerWorker.Activate(AddInToken pipeline, ActivationWorker& worker)

          at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)

          at System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(RuntimeMethodHandle md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)

          at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg, Int32 methodPtr, Boolean fExecuteInContext)

       Exception rethrown at [0]:

          at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

          at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

          at System.AddIn.Hosting.AddInServerWorker.Activate(AddInToken pipeline, ActivationWorker& worker)

          at System.AddIn.Hosting.AddInActivator.ActivateOutOfProcess[T](AddInToken token, AddInEnvironment environment, Boolean weOwn)

          at System.AddIn.Hosting.AddInActivator.Activate[T](AddInToken token, AddInProcess process, PermissionSet permissionSet)

          at System.AddIn.Hosting.AddInActivator.Activate[T](AddInToken token, AddInProcess process, AddInSecurityLevel level)

          at System.AddIn.Hosting.AddInToken.Activate[T](AddInProcess process, AddInSecurityLevel level)

          at DemoApplication.CalculatorHost.LoadAddIns() in C:projectsAppDomain Isolated WPF DemoDemoApplicationCalculatorHost.xaml.cs:line 213

     InnerException: System.InvalidOperationException

          Message="The calling thread must be STA, because many UI components require this."

          Source="PresentationCore"

          StackTrace:

               at System.Windows.Input.InputManager..ctor()

               at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()

               at System.Windows.Input.InputManager.get_Current()

               at System.Windows.Input.KeyboardNavigation..ctor()

               at System.Windows.FrameworkElement.EnsureFrameworkServices()

               at System.Windows.FrameworkElement..ctor()

               at System.Windows.Controls.Control..ctor()

               at System.Windows.Controls.Button..ctor()

               at GraphCalc.GraphingCalculator.StartButton() in C:projectsAppDomain Isolated WPF DemoGraphing CalculatorGraphingCalculator.cs:line 42

               at GraphCalc.GraphingCalculator..ctor() in C:projectsAppDomain Isolated WPF DemoGraphing CalculatorGraphingCalculator.cs:line 21

          InnerException:

    What can I do to resolve this?

    Thank you,

    Marcel

  10. Hi Jesse,

    I did tried to rebuild your sample on VS2008 RC, and i guess it needs updates. In the VisualCalculator…HostAdapter and same in Visual….AddInAdapter it gives 2 errors (same actuallz twice) that VisualAdapters do not exist in the context. I solve it by replacing it with FrameworkElementAdapters (however in case of Visual..AddInAdapter i had to cast to FrameworkElement which anyway derives from UIElement). Otherwise, it works perfectly. Thank you, C. Marius

  11. Marlun says:

    What about winforms? What if I wan’t the plugin to add a control to my host?

  12. Creating Add-Ins for WPF Applications [excerpts from upcoming SDK content] You’re unlikely to be reading

  13. You’re unlikely to be reading this if you haven’t used the .NET Framework to build managed applications

  14. Hola! I just returned from TechEd 2007 held in Barcelona, Spain. Barcelona is a beautiful city with incredible

  15. Hola! I just returned from TechEd 2007 held in Barcelona, Spain. Barcelona is a beautiful city with incredible

  16. Here is the latest in my link-listing series . Also check out my ASP.NET Tips, Tricks and Tutorials page

  17. Here is the latest in my link-listing series . Also check out my ASP.NET Tips, Tricks and Tutorials page

  18. fperdana says:

    This is a powerful feature, in which "an AppDomain isolated add-in generates some UI at the request of the host and the host displays directly as part of the application".

    Will this feature work with a WinForms add-in?

    Best Regards,

    Frank Perdana

  19. fperdana says:

    This is a powerful feature, in which "an AppDomain isolated add-in generates some UI at the request of the host and the host displays directly as part of the application".

    Will this feature work with a WinForms based add-in?

    Best regards,

    fperdana

  20. Markus Fischbacher says:

    First of all, great sample application!

    Now my problem:

    Today I’ve installed Visual Studio 2008 Pro Final.

    From now on, two methods are missing:

    VisualAdapters.ViewToContractAdapter

    VisualAdapters.ContractToViewAdapter

    Can anyone adapt the sample to get working with the final studio 2008?

    Thanks in advance!

    Greetings

    Markus

  21. Arne Janning says:

    The sample does not build out the box when using VS 2008 RTM and .NET 3.5 RTM since the "VisualAdapters"-Class in System.Windows.Presentation has been renamed to "FrameworkElementAdapters".

    So to make this work in .NET 3.5 RTM one has to change the Operate-method in the VisualCalculatorContractToViewHostAdapter-Class to this:

    public override UIElement Operate(

     HostView.Operation op,

     double[] operands)

    {

     return FrameworkElementAdapters.ContractToViewAdapter(

       _contract.Operate(

         OperationHostAdapters.ViewToContractAdapter(op),

         operands));

    }

    and the Operate-method in VisualCalculatorViewToContractAddInAdapter to this:

    public INativeHandleContract Operate(

     Calculator.Contracts.IOperationContract op,

     double[] operands)

    {

     return FrameworkElementAdapters.ViewToContractAdapter(

       _view.Operate(

       OperationViewToContractAddInAdapter.ContractToViewAdapter(op),

       operands) as FrameworkElement);

    }

    One also has keep in mind that the RTM-version of the ViewToContractAdapter-method expects a FrameworkElement-class instead of UIElement (Beta 2) therefore one has to cast explizitly.

    An updated version working with VS 2008 RTM an .NET 3.5 RTM can be downloaded here:

    http://www.mediafire.com/?fovat1ifx51

    Just wanted to share this, so if anyone runs into the same problem…

    BTW: Being an architect for a german ISV designing a new major application running entirely on .NET 3.5 I love this stuff. Great.

  22. Jim Galasyn says:

    Fyi, to build with release bits, you need to replace "VisualAdapters" with "FrameworkElementAdapters", like so.

    VisualCalculatorContractToViewHostAdapter.cs:

    public override UIElement Operate(HostView.Operation op, double[] operands)

    {

       return FrameworkElementAdapters.ContractToViewAdapter(

                   _contract.Operate(

                       OperationHostAdapters.ViewToContractAdapter(op),

                       operands));

    }

    VisualCalculatorViewToContractAddInAdapter.cs:

    public INativeHandleContract Operate(Calculator.Contracts.IOperationContract op, double[] operands)

    {

       return FrameworkElementAdapters.ViewToContractAdapter(

           _view.Operate(

               OperationViewToContractAddInAdapter.ContractToViewAdapter( op ),

               operands ) as FrameworkElement);

    }

    This is cool stuff, thanks for showing us how to do it.

  23. C. Marius says:

    Hi,

    I have an app. using the WPF add-in model presented here, and one of the add-Ins is a simple Wizard with various pages.

    I’ve used AddInSecurityLevel.Internet (constraints for security) to load the addIn, however I cannot launch a the wizard as Dialog box due to security restrictions on the Windows being launch for Internet activated add-Ins. Could you please advise any workarround ? Should I change design?

    Thanks, C. Marius

  24. Arne Janning says:

    The sample does not build out the box when using VS 2008 RTM and .NET 3.5 RTM since the "VisualAdapters"-Class in System.Windows.Presentation has been renamed to "FrameworkElementAdapters".

    So to make this work in .NET 3.5 RTM one has to change the Operate-method in the VisualCalculatorContractToViewHostAdapter-Class to this:

    public override UIElement Operate(

     HostView.Operation op,

     double[] operands)

    {

     return FrameworkElementAdapters.ContractToViewAdapter(

       _contract.Operate(

         OperationHostAdapters.ViewToContractAdapter(op),

         operands));

    }

    and the Operate-method in VisualCalculatorViewToContractAddInAdapter to this:

    public INativeHandleContract Operate(

     Calculator.Contracts.IOperationContract op,

     double[] operands)

    {

     return FrameworkElementAdapters.ViewToContractAdapter(

       _view.Operate(

       OperationViewToContractAddInAdapter.ContractToViewAdapter(op),

       operands) as FrameworkElement);

    }

    One also has keep in mind that the RTM-version of the ViewToContractAdapter-method expects a FrameworkElement-class instead of UIElement (Beta 2) therefore one has to cast explizitly.

    An updated version working with VS 2008 RTM an .NET 3.5 RTM can be downloaded here:

    http://www.mediafire.com/?fovat1ifx51

    Just wanted to share this, so if anyone runs into the same problem…

    BTW: Being an architect for a german ISV designing a new major application running entirely on .NET 3.5 I love this stuff. Great.

  25. Matt says:

    This sample does not build on v3.5 RTM.

    VisualAdapters.ContractToViewAdapter(…) no longer exists in System.AddIn.Pipeline namespace.

    There is System.AddIn.Pipeline.ContractAdapter.ContractToViewAdapter<TView>(…) but it has a different signature.  

    Can you please update this sample?  Thank you!

  26. Grahame says:

    When I attempt to build the example I get two errors:

    Error 1 – The name ‘VisualAdapters’ does not exist in the current context …HostSideAdaptersVisualCalculatorContractToViewHostAdapter.cs, line 34

    Error 2 – The name ‘VisualAdapters’ does not exist in the current context …AddInSideAdaptersVisualCalculatorViewToContractAddInAdapter.cs, line 31

    There are no classes in the solution called ‘VisualAdapters’. The methods being called on these classes (ContractToViewAdapter and ViewToContractAdapter) do exist (in AddInSideAdapters.OperationViewToContractAddInAdapter and HostSideAdapters.OperationHostAdapters) but have different signatures to the calls made on the error lines.

    This must have happened to others.  Is there a fix available?

  27. Keith Malwitz says:

    I am running VS2005 with version 3.5 of the framework. Is there a version of this sample app available for VS2005?

  28. Dathan says:

    We are working on a WPF application that loads add-ins into a separate AppDomain and those add-ins include visual content.  We are using the System.AddIn pipeline and therefore use FrameworkElementAdapters to marshal the UIElement references and the element shows up — excellent.  But some issues and questions:

    1. Routed events and command bindings do not ‘cross’ the appdomain boundary, meaning that common menu items (even simple ones like Paste) don’t work properly.
    2. The code for FrameworkElementAdapters appears to actually host the UIElement in a separate HWnd, which appears to mean that these UIElements, like hosted WinForms elements, have their own region and can’t be blended, combined, covered by other content.

    3. Most critically, though tabbing into the UIElement seems to work great navigation-wise, if you tab into the UIElement from, for example, a TextBox that is bound, then the TextBox you are leaving does not update it’s bound backer, presumably since the LostFocus event and other related events do not fire.  Essentially, it’s as though the keyboard focus never left the TextBox as far as the hosting window is concerned, even though the focus is clearly in the hosted UIElement.  CommandBindings on a menu like Paste still apply to the TextBox even though the focus is not there anymore.

    Can you comment on these issues?  Are these shortcomings of the current version?  Will they be fixed?  If not, what are the recommended workarounds so that added-in UIElements still behave like normal WPF content with respect to their hosting window?

    We are looking at rewriting our own version of MS.Internal.Controls.AddInHost and FrameworkElementAdapters to see if we can properly address the TabInto and general cross-domain focus issues, but that seems extreme.

    Thanks,

    Dathan

  29. Hua Wang says:

    Dathan,

    1. Rounted events and commands

    You are right. Those framework features do not work across appdomains out of box. You will need to wire them through contracts explicitly.

    1. Visual transitions

    Unfortunately this is a hard limit of hwnd hosting.

    We are aware of both of those issues (1 and 2). We are looking into improve the experience in future releases. We understand how inconvenient it can be for our customers at the mean time. Your feedback is appreciated.

    1. This issue seems to be a bug to me. We are currently investigating and will get back to you once we confirm it. Thanks for bringing this to our attention.

    Thanks,

    Hua

  30. Dathan says:

    Thanks Hua.  I have been able to globally solve 1 and 3 without any ‘invasive’ coding (i.e. no writing of our own element adapters or versions of MS…AddInHost, etc.), so I am good to go for now (I understand #2 is a hard limit).

    More info that may help: I wanted to test #3 after discovering #1 (no events made me wonder if focus events were getting handled, and that made me wonder about binding) — to test it I took the WPF demo app and added a 2-way bound text box in the tab order right before the stack of visual calculator plug ins.  The UI never saw the focus leave (i.e. the control’s property still shows it having focus, and RoutedCommands like a Paste menu still hit it as well).

    Any idea on when the ‘fix will be in’?

    Cheers, and thanks…. D

  31. John Bucci says:

    Can we see an example of wiring the Routed Events and Commands?

  32. Tooraj Helmi says:

    Is it required for the element to be the root element? I have a frame contained in a TabControl contained in a window. When I try to pass the frame, I get a "The element is not the root of the tree" exception.

    Thanks,

    Tooraj

  33. RobertT says:

    Hello everyone!

    I’m currently experiencing troubles with AddInHost! You see it draws just nothing when hosting window has AllowsTransparency property set to true! Is there any workaround? I really need this flag as the window I host visual addins in has complex bounds.

    Could you please duplicate an answer here: siniypin(alpha)gmail.com

    Best regards,

    Robert

  34. WPF.NET says:

    Jack had showed a Winforms UserControl(something with GreenBackground) from a AddIn which is being hosted on the Calculator window. But this one is missing on the attached WPF calculator sample. Do we have it somewhere?

    When I tried to Create an AddIn which contains a Winforms UserControl and host it on a Winfroms Form, it works fine.

    ** If I try to unload the AddIn, the main application is shut down**

    Can anyone create a simple example of How to create a AddIn with winforms UserControl and host it on a Winforms Form along with Unloading AddIn thing?

    Thanks in advance