Outlook功能区加载Inspector.CurrentItem为空

时间:2013-08-27 06:22:52

标签: c# vsto outlook-addin

概述

我有一个使用VSTO创建的Outlook加载项。该加载项具有Mail.Compose功能区类型的单个功能区(可视设计器)。功能区选项卡ControlIdType设置为“自定义”。除了设计器代码之外,加载项中唯一的代码是功能区的以下Load处理程序。 this.Context.CurrentItem意外返回null。

代码

private void RibbonComposeMail_Load(object sender, RibbonUIEventArgs e)
{
    try
    {
        var inspector = this.Context as Outlook.Inspector;
        if (inspector == null)
        {
            throw new ApplicationException("Fail - Step 1");
        }

        var currentMailItem = inspector.CurrentItem as Outlook.MailItem;
        if (currentMailItem == null)
        {
            throw new ApplicationException("Fail - Step 2");
        }

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

步骤

  1. 打开草稿电子邮件。功能区加载OK。
  2. 从收件箱中打开电子邮件。
  3. 打开相同的草稿电子邮件。功能区在步骤2失败,inspector.CurrentItem为空。
  4. 备注

    • 我在Outlook 2007,2010和2013中测试了这一点,在VS2010中创建了Outlook 2007和2010加载项,在VS2012中创建了Outlook 2010加载项。一切都表现得一样。
    • 反复打开草稿电子邮件似乎不会导致问题,必须在两者之间打开Email.Read检查器。
    • 功能区标签ControlidType很重要。 “自定义”将导致此问题,但“Office”的默认选项不会出现此问题。
    • 将场景翻转到其头部并将功能区类型设置为Mail.Read会产生相同的结果,前提是打开的顺序与Inbox>相反。草稿>收件箱(失败)。
    • Marshal.ReleaseComObjectinspector对象上currentMailItem的所有可能调用都没有区别。

3 个答案:

答案 0 :(得分:3)

我自己也有同样的问题。

我为Outlook日历约会设计了一个功能区栏,我想在每次约会时保存一些额外的字段(例如“此会议是否可以保存旅行?”)

我管理了它,但是,做起来很棘手。

正如您所说,当 Ribbon1_Load 函数启动时, ActiveInspector()为空...那么您应该如何获取有关当前的详细信息电子邮件或日历约会?

这是你需要做的。此示例基于日历约会,但很容易适应EmailItems。

首先,在ThisAddIn.cs文件中,您需要进行一些更改:

public partial class ThisAddIn
{
    Outlook.Inspectors inspectors;
    public static Outlook.AppointmentItem theCurrentAppointment;

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        inspectors = this.Application.Inspectors;
        inspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
    }

当用户打开或创建新的Outlook项目时,我们的“ Inspectors_NewInspector ”功能将被调用,此时,我们 能够获取有关该项的详细信息。项:

void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
     //  This function (apparently) gets kicked off whenever a user opens a new or existing item
     //  in Outlook (Calendar appointment, Email, etc).  
     //  We can intercept it, modify it's properties, before letting our Ribbon know about it's existance.
     //
     theCurrentAppointment = null;

     object item = Inspector.CurrentItem;
     if (item == null)
         return;

     if (!(item is Outlook.AppointmentItem))
         return;

     theCurrentAppointment = Inspector.CurrentItem as Outlook.AppointmentItem;
}

使用此代码,我们可以调整 Ribbon1_Load 函数来获取此“theCurrentAppointment”变量,并详细了解用户正在创建/修改的日历约会。

private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
     //  When this function gets called, "Globals.ThisAddIn.Application.ActiveInspector()" is always NULL, so we have
     //  to fetch the selected AppointmentItem via the ThisAddIn class.

     if (ThisAddIn.theCurrentAppointment != null)
     {
         //  Our Ribbon control contains a TextBox called "tbSubject"
         tbSubject.Text = ThisAddIn.theCurrentAppointment.Subject
     }
}

答案 1 :(得分:3)

麦克斯的评论有助于向我展示一些对这种行为更加好奇的事情。在第1步,RibbonComposeMail_Load事件被称为一次。但在第3步,它被称为两次。第一次在步骤3调用事件时,this.Context.CurrentItem为空,但第二次调用该事件时,该属性将保留该电子邮件。

它将NewInspector事件中的项目值与功能区Load事件中的项目值进行比较,这让我注意到了这一点。因为步骤3中的事件序列是:Ribbon_LoadNewInspectorRibbon_Load。我在Ribbon_Load中收到了MessageBox.ShowThisAddIn.CurrentMailItem邮件主题的主题,但是很惊讶地看到它是上一个电子邮件的主题,即第2步的收件箱电子邮件!

事实证明,如果Ribbon_Load为空,则解决方案是忽略this.Context.CurrentItem事件中的所有内容,因为第二个Ribbon_Load事件即将使用正确的值触发组。至于为什么我们在我的示例的第3步中看到了这种奇怪的行为,而不是第1步?对于实现Outlook对象模型的人来说,这可能是一个问题。

答案 2 :(得分:0)

我不是百分百肯定,但听起来垃圾收集器已经清除了你的内容.Context。

您是否可以尝试将您的Context置于私有字段中并从中获取currentitem:

private readonly Context _context = new Context(); 


private void RibbonComposeMail_Load(object sender, RibbonUIEventArgs e)
{
    try
    {
        var inspector = _context as Outlook.Inspector;
        if (inspector == null)
        {
            throw new ApplicationException("Fail - Step 1");
        }

        var currentMailItem = inspector.CurrentItem as Outlook.MailItem;
        if (currentMailItem == null)
        {
            throw new ApplicationException("Fail - Step 2");
        }

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

如果这没有帮助,我通常使用Outlook.Application对象来获取currentitem:

readonly Outlook._Application _application = new Outlook.Application();

var selectionList = _application.ActiveExplorer().Selection;

foreach (Object selObject in selectionList)
{
    if (selObject is Outlook.MailItem)
    {
        var outlookMail = (selObject as Outlook.MailItem);
    }
}

或者如果您只需要当前项目,就像您的情况一样:

var mailItem = _application.ActiveExplorer().Selection[0];