Outlook功能区加载检查器.CurrentItem为null

本文关键字:CurrentItem null 检查 功能区 加载 Outlook | 更新日期: 2023-09-27 18:29:11

概述

我有一个使用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. 打开草稿电子邮件。功能区加载正常
  2. 从收件箱打开电子邮件
  3. 打开相同的草稿电子邮件。功能区在步骤2失败,inspector.CurrentItem为空

备注

  • 我在Outlook 2007、2010和2013中测试过这一点,在VS2010中创建了Outlook 2007和2010加载项,在VS2012中创建了Outlook2010加载项。所有人的行为都一样
  • 反复打开草稿电子邮件似乎不会导致问题,必须在两者之间打开一个电子邮件阅读检查器
  • 功能区选项卡ControlidType很重要。"自定义"会导致此问题,但默认选项"Office"不会显示此问题
  • 如果打开顺序颠倒为"收件箱">"草稿">"收件箱"(失败),则翻转场景并将功能区类型设置为Mail.Read会得到相同的结果
  • inspectorcurrentMailItem对象上的Marshal.ReleaseComObject的调用的所有可能的排列没有区别

Outlook功能区加载检查器.CurrentItem为null

我自己也遇到过同样的问题。

我为Outlook日历约会设计了一个功能区栏,其中有一些额外的字段,我想在每次约会时保存(例如"这次会议节省旅行吗?")

我做到了,但是,这很难做到。

正如您所说,当您的Ribbon_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函数来接受这个"当前约会"变量,并阅读用户正在创建/修改的日历约会的详细信息。

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
     }
}

Mikes的评论让我对这种行为有了一些好奇。在步骤1中,RibbonComposeMail_Load事件被调用一次。但在第3步,它被称为两次。第一次在步骤3调用事件时,this.Context.CurrentItem为null,但第二次调用事件时该属性将保留电子邮件。

它将NewInspector事件中的项目值与ribbon Load事件中的值进行比较,这让我注意到了这一点。因为步骤3中的事件序列是:Ribbon_LoadNewInspectorRibbon_Load。我正在将Ribbon_LoadMessageBox.Show作为ThisAddIn.CurrentMailItem中邮件项目的主题,但很惊讶地发现它是以前打开的电子邮件的主题,即步骤2的收件箱电子邮件!

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

我不能100%确定,但听起来垃圾收集器已经清除了你的这个。上下文

你能试着把你的上下文放在一个私人字段中,并从中获取当前项吗:

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对象来获取当前项目:

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];