【问题标题】:Outlook item change events in C# misfiredC# 中的 Outlook 项目更改事件失败
【发布时间】:2022-04-28 09:13:39
【问题描述】:

我正在开发一个 Outlook 插件,它通过 PHP 与服务器通信。

我正在 Outlook 项目和服务器数据之间同步数据。

每当用户对某个项目进行更改(例如在约会日历中拖放到另一个日期,或更改某些值/注释等)时,都会触发项目更改事件,并且会发生同步.服务器有时会发回一些数据,即再次写入 Outlook 项目,但在这种情况下,事件被停用,因此没有级联。这一切都很好,但坏事来了:

我注意到一些非常奇怪的事情。在触发事件并且一切正常后,Outlook 有时会决定在几秒钟后(范围从 ~3 秒到 ~22 秒)再触发一次(甚至多次)事件。

这是非常不可预测的,而且非常烦人,因为同步依赖于由这些随机项目更改更改的项目 LastModificationTime。

有什么方法可以禁用这些事件,或者至少有什么方法可以将它们与实际用户操作区分开来?

我还使用 Add-In-Express 制作的插件监视了事件,并且我还在那里进行了一些奇怪的活动。

我在安装了不同版本的 Outlook/Windows 的多台 PC 上进行了尝试,几乎到处都会发生这种情况。

这里是我设置事件的地方:

public static Outlook.ItemsEvents_ItemChangeEventHandler AppointmentChangeHandler;
public static Outlook.ItemsEvents_ItemChangeEventHandler TaskChangeHandler;

public static Outlook.Items appointments = null;
public static Outlook.Items tasks = null;
public void SetupEventHandlers()
{
    Outlook.Application app = Globals.ThisAddIn.Application;
    Outlook.NameSpace ns = app.GetNamespace("mapi");
    Outlook.MAPIFolder calendar = null;
    Outlook.MAPIFolder tasksfolder = null;
    try
    {
        calendar = OutlookHelper.GetMAPIFolderByName("Calendar Where I want my events to work");
        if (calendar != null)
        {
            appointments = calendar.Items;
            AppointmentChangeHandler = new Outlook.ItemsEvents_ItemChangeEventHandler(Item_ItemChange);
            appointments.ItemChange += AppointmentChangeHandler;
        }
    }
    catch (Exception ex)
    {
        //failed to get calendar, and to add the itemchange event
    }

    try
    {
        tasksfolder = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);
        tasks = tasksfolder.Items;
        TaskChangeHandler = new Outlook.ItemsEvents_ItemChangeEventHandler(Item_ItemChange);
        tasks.ItemChange += TaskChangeHandler;
    }
    catch (Exception ex)
    {
        //failed to get tasks folder, and to add the itemchange event
    }
}

这是事件处理程序:

public static void Item_ItemChange(object Item)
{
        if (Item.LastModificationTime() > Item.LastSync().AddSeconds(2) && !ProgrammaticChange) //I try to do something here: checking if the lastmodification time is more than 2 seconds after the last synchronization time, but as i said, it sometimes adds 22 seconds, sometimes 0... 
        {
            ProgrammaticChange = true; //closing the door, so no cascading happens

            SyncItem(Item); //this can change values on the outlook items, that could eventually trigger another event, but the boolean flag is true, so the event will not happen

            ProgrammaticChange = false; //opening the door for new events
        }
}

【问题讨论】:

  • 您能出示一下代码吗,您已经有一段时间了。谢谢
  • 嗨杰里米!谢谢回复,我刚刚加了一些代码sn-ps。

标签: c# outlook vsto outlook-addin


【解决方案1】:

ItemChange 可以多次触发,即使是看似单一的更改。一个例子是在 OST 文件中创建一个项目,然后将其上传到 Exchange - 服务器调整项目,然后将更改下载到触发事件的客户端。

不要使用 ItemChange 事件作为唯一的同步入口点 - 如果在插件未运行时进行更改会发生什么?仅将其用作同步需要尽快运行而不是稍后运行的提示。

不仅如此,不要在事件处理程序中运行任何可能需要很长时间的东西 - 如果运行时间过长,下次可能不会为另一个项目触发该事件。将项目的条目 ID(但不是项目本身!)添加到列表中,您可以稍后在计时器或单独的线程中处理。

请记住,OOM 不能用于辅助线程(否则会引发异常)。您可以检索主线程上的所有数据,以便您的同步在辅助线程上完成所有繁重的工作,而无需触及 Outlook 对象。如果您需要在辅助线程中访问任何 Outlook 数据,扩展 MAPI(C++ 或 Delphi)或Redemption(我是它的作者 - 它包装了扩展 MAPI 并且可以从任何语言中使用)是您唯一的选择。在后一种情况下(赎回),您可以在主线程上缓存Namespace.MAPIOBJECT 属性的值(它返回IMAPISession MAPI 接口),然后在辅助线程上创建RDOSession 对象的实例并设置RDOSession.MAPIOBJECT 属性为保存在主线程上的值。然后,您可以使用 RDOSession.GetMessageFromID 通过其条目 ID 打开该项目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 2017-02-09
    • 2010-10-19
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    相关资源
    最近更新 更多