C#中的Outlook项目更改事件失败
我正在开发一个Outlook插件,它通过PHP与服务器通信 我正在同步Outlook项目和服务器数据之间的数据 每当用户对项目进行更改时(如将约会日历中的“拖放”到另一个日期,或更改某些值/注释等),就会触发项目更改事件,并发生同步。服务器有时会发回一些数据,也就是说,再次写入Outlook项目,但在这种情况下,事件被停用,因此没有级联。这一切都是好的,但坏的事情来了: 我注意到一些非常奇怪的事情。事件触发后,如果一切正常,Outlook有时会在几秒钟(从~3秒到~22秒)后决定再次触发事件一次(甚至多次) 这是非常不可预测的,而且非常烦人,因为同步依赖于这些随机项目更改所更改的项目LastModificationTime 有什么方法可以禁用这些事件,或者至少有什么方法可以将它们与实际用户操作区分开来 我还使用外接程序Express制作的加载项监视事件,并且在那里我还监视了一些奇怪的活动 我在多台PC上试用了它,安装了不同版本的Outlook/Windows,几乎到处都是 这里是我举办活动的地方:C#中的Outlook项目更改事件失败,c#,outlook,vsto,outlook-addin,C#,Outlook,Vsto,Outlook Addin,我正在开发一个Outlook插件,它通过PHP与服务器通信 我正在同步Outlook项目和服务器数据之间的数据 每当用户对项目进行更改时(如将约会日历中的“拖放”到另一个日期,或更改某些值/注释等),就会触发项目更改事件,并发生同步。服务器有时会发回一些数据,也就是说,再次写入Outlook项目,但在这种情况下,事件被停用,因此没有级联。这一切都是好的,但坏的事情来了: 我注意到一些非常奇怪的事情。事件触发后,如果一切正常,Outlook有时会在几秒钟(从~3秒到~22秒)后决定再次触发事件一次
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打开该项目。您可以显示代码吗,您已经使用了一段时间了。谢谢杰里米!谢谢你的回复,我刚刚添加了一些代码片段。