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