展望2016
.Net框架4.5下,在收集第一個項目的#前景插件userproperty沒有找到
我遇到一個非常奇怪的現象: 當我通過一個聯繫人文件夾的項目集合中一些非常特殊的不確定迭代案例(我不明白)收集的第一個項目的某些用戶屬性無法加載。但是,UserProperties被明確設置。
的方法如下:
I open the contact folder (to which the items will be moved) in outlook.
then i execute the "test"
the execution of the test can be suammrized as following:
click button ->
start thread
iterate through the items (on first iteration no items are present).
add new items{
create item
set userproperty PRE before item is initially saved
save item
move item to desired folder
set userproperty POST after item is moved
save item
}
end thread
click button ->
start thread
iterate through the items (here the userproperty POST sometimes fails to load on the first item of the collection, however when i investigate it, it IS there. It only fails for the first item and succeeds for every other following item).
...END
在我看來是莫名其妙的前景沒有及時更新userproperty定義。但請注意,第一個BackgroundWorker線程在使用第二個BackgroundWorker線程遍歷項目時已經完成。 這個問題可能與iam在添加和迭代項目時在資源管理器中查看文件夾有關。 這個錯誤很難重現,而且很少發生。但是我真的很缺乏洞察內部工作的前景,所以我只能推測。
解決方法的建議: 我可以在移動它之前添加一個包含所有用戶屬性的項目。這裏的問題是我需要添加新的用戶屬性,在項目最初保存並移動到文件夾後,在某些情況下。 在少數情況下,userproperty鍵是動態創建的(使用模式),因此預定義所有用戶屬性將不是最佳選擇。 UserProperties可靠地加載是非常重要的,因爲一些重要的特性是基於它們的。
有沒有人有線索如何導致問題,以及如何解決它?因爲這種行爲令我瘋狂。
一些代碼(不是原來的,但它應該包含所有相關方面)
//Ribbon
TestNS.TestCaller testCaller;
string folderID = "00000000BDB409934ED327439481EB6E1E1CC4D3010055B62301B58E32478DCD8C0D3FA6304600002C4CA4400000";
public void testButton0_Action(Office.IRibbonControl control)
{
if(testCaller == null){
testCaller = new TestNS.TestCaller(ThisAddIn.Outlook,folderID);
}
testCaller.Run();
}
//Ribbon end
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
namespace TestNS
{
public class TestCaller{
private Outlook.Application application;
private BackgroundWorker worker = new BackgroundWorker();
private Test test = null;
private string folderId;
private bool init = true;
private bool busy = false;
public TestCaller(Outlook.Application application, string folderId){
this.application = application;
this.folderId = folderId;
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnCompleted);
}
public void Run()
{
if (!busy)
{
busy = true;
test = new Test(application, folderId, init);
worker.RunWorkerAsync();
}
}
private void DoWork(object sender, DoWorkEventArgs e)
{
test.Process();
test = null;
}
private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
{
busy = false;
init = false;
}
}
class Test
{
public const string key_preCreateProperty ="preCreate";
public const string key_postCreateProperty = "postCreate";
private Outlook.Application application;
private string folderId;
private bool createData;
public Test(Outlook.Application application,string folderId,bool createData)
{
this.application = application;
this.folderId = folderId;
this.createData = createData;
}
public void Process(){
Examine();
if(createData){
CreateData();
}
}
public void CreateData()
{
List<Poco> pocos = new List<Poco>();
for (int i = 0; i < 10; i++)
{
pocos.Add(
new Poco
{
Pre = "Pre" + i,
Post = "Post" + i
}
);
}
CreateContactItems(folderId,pocos);
}
public void Examine()
{
bool preIsLoaded = false;
bool postIsLoaded = false;
Debug.WriteLine(">>>Examine");
Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
Outlook.Items folderItems = folder.Items;
int i = 0;
//print UserProperties registered to the items
foreach(Outlook.ContactItem contactItem in folderItems){
var itemUserProperties = contactItem.UserProperties;
string itemUserPropertiesString = "";
foreach (var itemProp in itemUserProperties)
{
Outlook.UserProperty prop = (Outlook.UserProperty)itemProp;
itemUserPropertiesString += " " +prop.Name + " " + prop.Value + " \n";
}
//HERE: sometimes it prints only Pre on the first index of the iteration
Debug.WriteLine(string.Format("i={0} , itemUserProperties Count={1} , following UserProperties: \n{2}", i++, itemUserProperties.Count, itemUserPropertiesString));
string pre = null;
string post = null;
try
{
pre = contactItem.GetUserProperty(key_preCreateProperty);
preIsLoaded = true;
}
catch(KeyNotFoundException ex){
Debug.WriteLine("Error: Pre Not found"); //should not happen - doesn't happen
}
try
{
post = contactItem.GetUserProperty(key_postCreateProperty);
postIsLoaded = true;
}
catch (KeyNotFoundException ex)
{
Debug.WriteLine("Error: Post Not found"); //shoul not happen - happens rarely totally indeterminitic
}
Marshal.ReleaseComObject(itemUserProperties);
}
Debug.WriteLine("<<<Examine");
if (folderItems.Count > 0 && (!preIsLoaded || !postIsLoaded))
{
MessageBox.Show("preIsLoaded="+preIsLoaded +" \n" +"postIsLoaded="+postIsLoaded);
}
Marshal.ReleaseComObject(folderItems);
Marshal.ReleaseComObject(folder);
}
public void CreateContactItems(string folderId,List<Poco> pocos)
{
Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
foreach(Poco poco in pocos){
CreateContactItem(folder,poco);
}
Marshal.ReleaseComObject(folder);
}
public void CreateContactItem(Outlook.MAPIFolder testFolder,Poco data)
{
Outlook.ContactItem contactItem = application.CreateItem(Outlook.OlItemType.olContactItem);
contactItem.SetUserProperty(key_preCreateProperty, data.Pre);
contactItem.Save();
Outlook.ContactItem movedContactItem = (Outlook.ContactItem)contactItem.Move(testFolder);
Marshal.ReleaseComObject(contactItem);
contactItem = movedContactItem;
contactItem.FirstName = data.Pre;
contactItem.LastName = data.Post;
contactItem.SetUserProperty(key_postCreateProperty, data.Post);
contactItem.Save();
Marshal.ReleaseComObject(contactItem);
}
}
public static class Util
{
public static void SetUserProperty(this Outlook.ContactItem item, string name, dynamic value)
{
Outlook.UserProperty property = item.UserProperties[name];
if (property == null)
{
property = item.UserProperties.Add(name, Outlook.OlUserPropertyType.olText);
}
property.Value = value;
}
public static dynamic GetUserProperty(this Outlook.ContactItem item, string name)
{
Outlook.UserProperty property = item.UserProperties[name];
if (property != null)
{
return property.Value;
}
throw new KeyNotFoundException(string.Format("UserProperty name={0} not found", name));
}
}
public class Poco
{
public string Pre
{
get;
set;
}
public string Post
{
get;
set;
}
}
}
感謝您
感謝您的快速答覆。對於我的困惑...我曾經使用過Outlook 2010,但幾個星期以來,我使用的Outlook 365幾乎應該是Outlook 2016.至少它確實看起來完全相同。當我嘗試訪問OOM – FreeG
時,可悲的是該進程需要在後臺運行,因爲它將聯繫人與ERP系統同步。有沒有辦法在後臺處理聯繫人,而不會出現奇怪的行爲。是直接使用擴展MAPI還是會導致意外行爲? – FreeG
擴展MAPI需要C++或Delphi。您可以嘗試使用Redemption - 可以在輔助線程上使用RDO系列對象。 –