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