Partager via


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

  • Anonymous
    August 06, 2007
    The comment has been removed

  • Anonymous
    August 09, 2007
    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=1The 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

  • Anonymous
    August 13, 2007
    The comment has been removed

  • Anonymous
    August 14, 2007
    The comment has been removed

  • Anonymous
    August 21, 2007
    OT, but is there an MSDN forum for Add-Ins?

  • Anonymous
    August 23, 2007
    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

  • Anonymous
    August 30, 2007
    A somewhat awkward but necessary first step... I am a Software Development Engineer on the WPF Application

  • Anonymous
    October 15, 2007
    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.dllAdditional 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");               f.Width = 200;               f.Height = 200;           }           else           {               f.Source = new Uri("http://www.microsoft.com");           }           return f;       }

  • Anonymous
    October 22, 2007
    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

  • Anonymous
    October 28, 2007
    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

  • Anonymous
    November 06, 2007
    What about winforms? What if I wan't the plugin to add a control to my host?

  • Anonymous
    November 09, 2007
    Creating Add-Ins for WPF Applications [excerpts from upcoming SDK content] You’re unlikely to be reading

  • Anonymous
    November 09, 2007
    You’re unlikely to be reading this if you haven’t used the .NET Framework to build managed applications

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

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

  • Anonymous
    November 17, 2007
    The comment has been removed

  • Anonymous
    November 17, 2007
    The comment has been removed

  • Anonymous
    November 19, 2007
    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

  • Anonymous
    November 19, 2007
    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

  • Anonymous
    November 21, 2007
    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.ViewToContractAdapterVisualAdapters.ContractToViewAdapterCan anyone adapt the sample to get working with the final studio 2008?Thanks in advance!GreetingsMarkus

  • Anonymous
    November 22, 2007
    The comment has been removed

  • Anonymous
    November 26, 2007
    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.

  • Anonymous
    November 30, 2007
    The comment has been removed

  • Anonymous
    December 02, 2007
    The comment has been removed

  • Anonymous
    December 05, 2007
    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!

  • Anonymous
    December 06, 2007
    The comment has been removed

  • Anonymous
    December 28, 2007
    I am running VS2005 with version 3.5 of the framework. Is there a version of this sample app available for VS2005?

  • Anonymous
    January 28, 2008
    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: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.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. 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

  • Anonymous
    January 28, 2008
    The comment has been removed

  • Anonymous
    January 29, 2008
    The comment has been removed

  • Anonymous
    February 11, 2008
    Can we see an example of wiring the Routed Events and Commands?

  • Anonymous
    April 03, 2008
    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

  • Anonymous
    June 04, 2008
    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.comBest regards,Robert

  • Anonymous
    July 09, 2008
    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