Tips & Tricks - .Net Control Add-in Ready Event

For a while now I have been creating .Net add-in controls for Dynamics NAV (2009 R2 - 2013 R2). One thing I learned early on (and which Vjekoslav Babic has mentioned here, I suggest you read that first in order to make sense of this post) is that you need to ensure your control add-in has been instantiated before you try to access it via NAV. If you do not do this you will receive a similar error as shown below (image courtesy of Vjekoslav Babic's website):

Add-In Control Has Not Been Instantiated
Control Add-in Has Not Been Instantiated
Unfortunately, trying to access your control in a trigger such as OnOpenPage does not guarantee that the control has been instantiated first. There are many other approaches you may think to try (checking for null etc.), but most of these will not work as expected.

To combat the error, you need to have your control send a custom event, such as ControlAddInReady, when it is instantiated. This needs to be set up on the .Net side.


If you read Vjekoslav Babic's post, you will see that the custom event needs to be defined in your control add-in and triggered to fire inside of the CreateControl override after your control is instantiated. The recommended trigger to fire the custom event is often the Control.OnParentChanged event. This is what that would look like (I do thinks slightly differently than Vjekoslav, so this may look a slightly different than you are used to):


[ControlAddInExport("My Fancy Thing Addin Control")]
public class MyFancyThingAddinControl : WinFormsControlAddInBase
{
    private MyFancyThing _myFancyThing;

    [ApplicationVisible]
    // no need for null checks later
    public event MethodInvoker ControlAddInReady = delegate { };

    protected override Control CreateControl()
    {
        _myFancyThing = new MyFancyThing();
        _myFancyThing.ParentChanged += (sender, e) => ControlAddInReady();

        return _myFancyThing;
    }
}

The problem with this approach is that the Control.OnParentChanged event can actually fire more than once. In most cases this is not an issue. However, I have created some very complex control add-ins that are full-blown WPF controls wrapped inside of an ElementHost (WinForms container). In addition to this, I have had some expensive initialization logic such as assigning implementations of various interfaces that are decided in the NAV code at runtime (another blog post to come on this,which is a great way to run test logic). This is the type of stuff that I neither want nor require to fire more than once. So rather than using the Control.OnParentChanged event, a better choice is the Control.HandleCreatedEvent. This will only fire a single time for the given control and will ensure that your control is instantiated before you try to access it from NAV. This looks like the following:


protected override Control CreateControl()
{
    _myFancyThing = new MyFancyThing();
    _myFancyThing.HandleCreated += (sender, e) => ControlAddInReady();

     return _myFancyThing;
}

Disclaimer: Even though he has not shown this in his blog, it was Vjekoslav Babic himself that mentioned this at NAV Tech Days 2014 during one of his sessions. He had given credit to Arend-Jan Kauffmann about this tip.

Labels: , , , , , , , ,