softwaregreenhouses.com Blog

January 13, 2008

Part II – Windows Controls Extensibility with .NET 3.5 CLR Add-Ins using WPF and Crossbow

Filed under: .NET 3.5 CLR AddIn, Crossbow, WPF — Marty Nelson @ 8:59 pm

In an earlier post, I described a method of hosting windows controls that relied on a hidden form on the add-in side that hosted the add-in control, but appeared in a designated area of the host form.

There has been continued interest in using CLR Add-Ins with Windows Form, see the CLR Team’s post Support for Windows Forms in Hosts and Add-Ins.

While it work well graphically, some of the more detailed integration of ALT+ and CTRL+ keys, tab order, etc. did not work entirely well.

Following the advice of the Jesse Kaplan at the Microsoft CLR Add-In team, I have created a new sample using WPF and Crossbow to handle the pseudo-marshalling of the windows control.

This example uses VS2005 and, other than the add-in pipeline itself, it is, from the perspective of the host and add-in developer, a *pure* Windows Forms experience.

>>Download Solution Here

With the built in adapters for WPF in System.AddIn.Pipeline, in addition to WPF/Windows interop available via Crossbow (or the should I say the project formally know as Crossbow?), the code becomes almost trivial.

Here’s a quick run down of the pipeline:

The Add-In View

[AddInBase]

public interface IAddInControl

{

    Control GetControl();

}

The Add-In Side Adapter

[AddInAdapter]

public class AddInControlVca : ContractBase, IAddInControlContract

{

    private readonly IAddInControl addInControl_;

 

    public AddInControlVca(IAddInControl addInControl)

    {

        addInControl_ = addInControl;

    }

 

    #region IAddInControlContract Members

 

    public INativeHandleContract GetControl()

    {

        WindowsFormsHost host = new WindowsFormsHost();

        host.Child = addInControl_.GetControl();

        return FrameworkElementAdapters.ViewToContractAdapter(host);

    }

 

    #endregion

}

The Contract

[AddInContract]

public interface IAddInControlContract : IContract

{

    INativeHandleContract GetControl();

}

The Host Side Adapter

[HostAdapter]

public class AddInControlCva : ElementHost

{

    private readonly ContractHandle contractHandle_;

 

    public AddInControlCva(IAddInControlContract contract)

    {

        Child = FrameworkElementAdapters.ContractToViewAdapter(contract.GetControl());

        contractHandle_ = new ContractHandle(contract);

    }

}

Consuming The Add-In

Collection<AddInToken> tokens = GetAddInTokens();

foreach (AddInToken token in tokens)

{

    TabPage page = new TabPage(token.AddInFullName);

    tabControl1.TabPages.Add(page);

    Control addInControl = token.Activate<Control>(

        AddInSecurityLevel.FullTrust,

        string.Format(“AddInControlDomain{0}”,

            tabControl1.TabPages.IndexOf(page)));

    addInControl.Dock = DockStyle.Fill;

    page.Controls.Add(addInControl);

}

 

11 Comments »

  1. [...] I wrote this initial example before Jesse Kaplan suggested using WPF and Crossbow to implement Windows Control Add-in integration.  My newer post here describes this technique.  The approach below may still be valid if seen as a *lightweight* technique if the overhead of loading WPF is too great and Hot Key integration is not important. [...]

    Pingback by software greenhouses » Windows Controls Extensibility with .NET 3.5 CLR Add-Ins Using a “Leased-Space” Model — January 14, 2008 @ 2:00 am

  2. How do you do what your sample above achieves but using FORMS, not user controls?

    Comment by Eric Brand — February 15, 2008 @ 7:48 pm

  3. Thanks for this article.
    I was wondering – givin the security demand for FullTrust inside of the WindowsFormsHost, how would one host Windows Forms controls inside of AddIns that are only partially trusted (much of the reason that I use AddIns is becuase I can limit their capabilities).

    Comment by Adam Langley — March 5, 2008 @ 9:17 pm

  4. @Eric Brand

    Why would you need to marshall the form to the host side? Why not just run it on the add-in side?

    Or are you thinking of an MDI scenario? In that case I would have a host form on the host side and just fill it with a control from the add-in side…

    Comment by Marty Nelson — April 6, 2008 @ 9:24 pm

  5. @Adam -

    I haven’t tried it with different security settings yet. My understanding is that the handle to the add-in control is a fairly low-level Win32 handle, so it’s mostly rendering and eventing, the add-in control code is still running on it’s own side.

    Comment by Marty Nelson — April 6, 2008 @ 9:26 pm

  6. Hi!,
    i tried the solution and it works great, but is there a way to change the activation of the AddIn??

    i’m using spring, and i’ve configured the user controls in my config file, but everytime an addin gets activated, it creates a new instance of the Control without actually querying spring for the configured instance, ( i’ve modified the Control GetControl() method to get the actual spring instance ) but i still have two instances of the same control….

    another question is, why is the behavior of special keys like tab and ctrl+ and alt+ keys changed?? is there anyway to fix this issue??

    thanks!

    Comment by Leonardo — May 21, 2008 @ 10:19 pm

  7. Leonardo -

    When you activate an add-in, it is going to create a new one, that’s just how CLR add-in’s work. So you need to hold on to the activated instance if you want to reuse the underlying control. So you might go through a caching class of some kind that looks up the add by token name and either returns the already activated add-in if it exists, or activates (creates) it if it doesn’t and adds it to the cache.

    The issue with ctrl+ and alt+ keys should work fine with the WPF/Windows interop. It was my first attempt without the interop that had these deficiencies.

    Comment by Marty Nelson — May 28, 2008 @ 3:56 am

  8. Thanks Marty,

    About the control and alt keys, they do act strange on a modified version of your sample.

    I modded the sample to create a MDI parent form, each of the HostedControls get inserted on a new form instance, everything seems fine until you press the control key or Tab+, the expected behavior would be to change the focus on each of the controls inside the form, but, the behavior i get is swapping between the different hosted forms in the mdi, maybe i’m doing something wrong, but i just wanted to know your comment to see if you get the same behavior.

    thanks for your comments

    Comment by Leonardo — June 9, 2008 @ 2:34 pm

  9. Hi,

    Is it to possible to unload the AppDomain where Add-in was created? When I tried to uload the add-in’s AppDomain, it closes the main application silently. Please find below the code I tried and advise me if something is wrong here.

    private void somethingToolStripMenuItem_Click(object sender, EventArgs e)
    {
    MessageBox.Show(”Something”);

    Control ctrl = tabControl1.TabPages[0].Controls[0];
    tabControl1.TabPages.RemoveAt(0);
    AppDomain domain = AddInController.GetAddInController(ctrl).AppDomain;
    ctrl = null;
    GC.Collect();
    AppDomain.Unload(domain);
    }

    Thanks in advance.

    Comment by Ram — June 30, 2008 @ 2:11 am

  10. Could you please post a code snippet on how to uload the AppDomain in your sample?

    Comment by Mike — June 30, 2008 @ 1:11 pm

  11. What about loading the add-ins in a separate process?

    I tried this and I get an error telling me the control can’t be created because the thread isn’t STA. Any idea how to get the creation thread STA using a separate process?

    Comment by Judah Himango — March 5, 2009 @ 4:56 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress