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

时间:2017-05-03 09:31:46

标签: c# outlook vsto outlook-addin

我正在开发一个Outlook加载项,它通过PHP与服务器通信。

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

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

我注意到一些奇怪的事情。在事件被触发后,一切都是正确的,Outlook有时会在几秒钟后(从大约3秒到大约22秒)再决定再次发起事件(甚至多次)。

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

任何禁用这些事件的方法,或者至少是将它们与实际用户操作区别开来的方法吗?

我还使用Add-In-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
        }
}

1 个答案:

答案 0 :(得分:0)

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

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

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

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

按条目ID打开该项目