C#中的Outlook项目更改事件失败

C#中的Outlook项目更改事件失败,c#,outlook,vsto,outlook-addin,C#,Outlook,Vsto,Outlook Addin,我正在开发一个Outlook插件,它通过PHP与服务器通信 我正在同步Outlook项目和服务器数据之间的数据 每当用户对项目进行更改时(如将约会日历中的“拖放”到另一个日期,或更改某些值/注释等),就会触发项目更改事件,并发生同步。服务器有时会发回一些数据,也就是说,再次写入Outlook项目,但在这种情况下,事件被停用,因此没有级联。这一切都是好的,但坏的事情来了: 我注意到一些非常奇怪的事情。事件触发后,如果一切正常,Outlook有时会在几秒钟(从~3秒到~22秒)后决定再次触发事件一次

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

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

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

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

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

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

我还使用外接程序Express制作的加载项监视事件,并且在那里我还监视了一些奇怪的活动

我在多台PC上试用了它,安装了不同版本的Outlook/Windows,几乎到处都是

这里是我举办活动的地方:

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

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

不要将ItemChange事件用作唯一的同步入口点-如果在加载项未运行时进行更改,会发生什么情况?仅将其用作提示同步需要尽早运行,而不是推迟运行

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


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

您可以显示代码吗,您已经使用了一段时间了。谢谢杰里米!谢谢你的回复,我刚刚添加了一些代码片段。