9

我正在尝试为 Excel VSTO 项目配置 DI。

为给定工作表生成的代码隐藏为我提供了一个名为 Startup 的事件,该事件负责为 Startup、Change、BeforeDoubleClick 等事件设置事件处理程序。

我认为通常避免代码隐藏文件中的代码是一个好习惯。
我所做的是创建负责操作工作表并调用外部代码(如 Web 服务、数据库和域逻辑)的外部类。

我可以成功创建一个工厂供代码隐藏文件使用并实例化工作表逻辑类。

例如:

//...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

上面的代码位于 Visual Studio 生成的代码隐藏文件中,而且它是最小的。显示弹出窗口的责任委托给不同的对象。工厂对象负责与 Ninject 交谈并为我获取对象。这个代理是使用 Ninject.Extensions.Factory 项目自动生成的,因为我通过了这样的接口:

/// <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();
}

在应用程序启动中,我为工厂本身定义了绑定和绑定:

//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();

问题是:

如何在 VSTO 工作表的生成代码中注入这个工厂?我不喜欢_kernel.Get<IExpenseWorksheetFactory>在工作表的 Startup 方法中调用的想法。是否可以查找 Sheet1 的所有可用实例并强制注入工厂?

4

1 回答 1

3

简短的回答:没有。

您正在寻找像构造函数注入这样的东西,它无疑读起来更优雅。但事实上,这是不可能的,因为您无权访问 VSTO 插件中的 c'tor。

但无论如何,打电话有什么不好_kernel.Get<IExpenseWorksheetFactory>?毕竟,显式调用 DI 容器来解决依赖关系是其正常用例之一,而代码隐藏文件正是为此而制作的:连接事物。

你是对的,代码隐藏不应该包含任何业务逻辑,但另一方面,它肯定应该包含连接事物所需的所有代码。这就是它存在的主要原因。或者,换句话说:

我认为通常避免代码隐藏文件中的代码是一个好习惯。

并非在每种情况下都是正确的(但仅适用于绝大多数情况),您不应该在这里过度使用。如果你这样做了,你会发现自己在与系统作斗争——记住,系统总是会赢的 ;-)...

于 2014-10-01T07:34:32.880 回答