I'm trying to configure DI for an Excel VSTO project.
The generated code-behind for a given worksheet offers me a event called Startup, which is reponsible to set event handlers for events like Startup, Change, BeforeDoubleClick and so on.
I think is generally a good practice do avoid code in code-behind files.
What I do is create external classes that are responsible to manipulate the worksheet and call external code like web services, databases and domain logic.
I can create successfully a Factory to be consumed by the codebehind file and instantiate the worksheet logic class.
For example:
//...inside Sheet1.cs
private IExpenseWorksheetFactory _factory;
void ExpensesBeforeRightClick(Excel.Range target, ref bool cancel)
{
Application.EnableEvents = false;
var popup = _factory.CreateContextMenu();
popup.ShowContextMenu(target, ref cancel);
Application.EnableEvents = true;
}
// ... rest of Sheet1.cs
The code above is inside the code-behind file Visual Studio generates and it's minimal. The responsibility to show the popup is delegated to a distinct object. The factory object is responsible to talk with Ninject and get the object for me. This proxy is generated automatically using Ninject.Extensions.Factory project as I pass an interface like this:
/// <summary>
/// Abstract Factory for creating Worksheet logic objects. Meant to be used with Ninject Factory extension.
/// </summary>
public interface IExpenseWorksheetFactory
{
ExpenseWorksheet CreateWorksheet();
ExpenseWorksheet.ContextMenus CreateContextMenu();
ExpenseWorksheet.Events CreateEventHandlers();
}
In the application startup, I have defined the the bindings and the binding for the factory itself:
//instantiate the kernel in app's Composition Root
_kernel = new StandardKernel();
//worksheet related stuff - seems to be ok to be singleton
_kernel.Bind<ExpenseWorksheet>().ToSelf().InSingletonScope();
_kernel.Bind<ExpenseWorksheet.Events>().ToSelf().InSingletonScope();
_kernel.Bind<ExpenseWorksheet.ContextMenus>().ToSelf().InSingletonScope();
//"automagic" factories
_kernel.Bind<IExpenseWorksheetFactory>().ToFactory();
The problem is:
How can I inject this factory in the generated code of VSTO worksheet? I don't like the idea of calling _kernel.Get<IExpenseWorksheetFactory>
inside the Startup method of the worksheet. Is it possible to look for all available instances of Sheet1 and force the injection of the factory?