代码之家  ›  专栏  ›  技术社区  ›  ScottishTapWater

获取共享的Outlook日历事件C#

  •  0
  • ScottishTapWater  · 技术社区  · 6 年前

    我知道如何检索当前用户的outlook日历中的事件,下面的代码可用于删除与特定模式匹配的项,例如:

    private void RemoveAppointments()
            {
                Outlook.Application outlook = new Outlook.Application();
                Outlook.MAPIFolder calendarFolder = outlook.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
                Outlook.Items outlookCalendarItems = calendarFolder.Items;
                for (int i = outlookCalendarItems.Count; i > 0; i--)
                {
                    if (outlookCalendarItems[i].Subject.Contains("On Call: Regions:") && outlookCalendarItems[i].Start.Year == _year)
                    {
                        outlookCalendarItems[i].Delete();
                    }
                }
            }
    

    我能从哪里开始吗?


    注意:这是使用Outlook的日历窗格表示团队的方式。修订了敏感细节。

    Calendar Section Bar

    2 回复  |  直到 6 年前
        1
  •  1
  •   Dmitry Streblechenko    6 年前

    而不是使用 Namespace.GetDefaultFolder Namespace.GetSharedDefaultFolder ,通过 Recipient 从返回的对象 Namespace.CreateRecipient .

    全部的 文件夹中的项目是一个可怕的想法,特别是如果您打开的联机文件夹没有缓存在本地OST文件中。使用 Items.Find/FindNext Items.Restrict 相反。

        2
  •  1
  •   ScottishTapWater    6 年前

    感谢@Dmitry his answer 这帮我解决了我的问题。然而,为了最大限度地利用这个问题为未来的读者,我想我会扩大它。


    假设:

    using Microsoft.Office.Interop.Outlook;
    

    COM程序集 Microsoft Outlook 16.0 Object Library


    Outlook.Application 对象,该对象用作Outlook函数的接口(可以将其视为完整Outlook程序的内部实例):

    Application app = new Application();
    

    然后,我从与团队关联的全局地址列表的通讯组列表中提取所有用户。这是通过创建 Recipient 对象来自 Session Application 实例。

    Recipient distList = app.Session.CreateRecipient(yourDistList);
    

    从这里我们可以把所有的实名和用户名 AdressEntry.Members 收件人的财产。把这两个放入 (string,string)

    List<(string,string)> usersData = distList.AddressEntry.Members.Cast<AddressEntry>().Select(entry => (entry.Name,entry.Address)).ToList();
    

    现在,给定一个特定的用户名,只要日历已经与curernt用户共享,就可以使用 GetSharedDefaultFolder() 方法 会议 :

    MAPIFolder sharedCalendar = _app.Session.GetSharedDefaultFolder(teamMember, OlDefaultFolders.olFolderCalendar);
    

    在这一点上,我发现做一些过滤来避免最常见的 COMException 但是,有很多我似乎无法确定的原因,所以我只是 catch (COMException) 把它们扔掉。我知道这不是一个好的做法,但它似乎不会妨碍我访问我有权限访问的日历。一些(非常)基本的过滤:

    if (sharedCalendar.DefaultMessageClass != "IPM.Appointment" || teamMember.DisplayType != 0)
    {
        return null; //Calendar not shared.
    }
    

    现在我们必须建立一个 Filter 字符串使用Microsoft Outlook格式,可以使用以下语句(其中 from to 两者都是 DateTime

    string sFilter = $"[End] > '{from:g}' AND [Start] < '{to:g}' AND [Recurring] = 'No'";
    

    我们过滤掉重复发生的事件,否则开始和结束日期可能会大大超出范围,而不会出现内部事件。出于我的目的,我不需要经常性的事件,但是,如果你这样做,你将不得不单独处理这个。

    最后,我们现在可以利用 Items.Restrict() 方法 MAPIFolder

    Items results = sharedCalendar.Items.Restrict(sFilter);
    

    这将返回 Items 接口到属于我们过滤器的所有项。

    最后,我们可以对每个项进行迭代(我以相反的顺序迭代,因为我从我的旧应用程序中复制了删除事件的代码,但在这种情况下这不重要)。你可能得把 object AppointmentItem

    List<AppData> appointments = new List<AppData>();
    for (int i = results.Count; i > 0; i--)
    {
        appointments.Add(new AppData(results[i], username));
    }
    

    我将每个事件存储为 AppData 结构只保留我需要的数据:

    public struct AppData
    {
        public string Subject { get; }
        public DateTime From { get; }      
        public DateTime To { get; }       
        public string Location { get; }      
        public string Categories { get; }      
        public string Username { get; }
        public AppData(AppointmentItem appItem, string username)
        {
            Subject = appItem.Subject;
            From = appItem.Start;
            To = appItem.End;
            Location = appItem.Location;
            Categories = appItem.Categories;
            Username = username;
        }
    }
    

    所有这些都会产生这样一个类:

    public class OutlookCommunicator : IDisposable
    {
        private readonly Application _app;
    
        public OutlookCommunicator()
        {
            _app = new Application();
        }
    
        /// <summary>
        /// Username of the distribution list according to the GAL.
        /// </summary>
        private const string DistList = "redacted";
    
        /// <summary>
        /// Fetches a list of all usernames and names within the DistList.
        /// </summary>
        /// <returns>List&lt;string&gt; containing all usernames.</returns>
        public List<(string,string)> GetUsers()
        {
                Recipient warEngineering = _app.Session.CreateRecipient(DistList);
                List<(string,string)> usernames = warEngineering.AddressEntry.Members.Cast<AddressEntry>().Select(entry => (entry.Name,entry.Address)).ToList();
                return usernames;
    
        }
    
    
    
        /// <summary>
        /// Fetches all calendar events for a user falling within the provided range.
        /// </summary>
        /// <param name="from">Start search date.</param>
        /// <param name="to">End search dat.</param>
        /// <param name="username">User's calendar to search.</param>
        /// <returns></returns>
        public List<AppData> GetEventsInRange(DateTime from, DateTime to, string username)
        {
            List<AppData> appointments = new List<AppData>();
            try
            {
    
                Recipient teamMember = _app.Session.CreateRecipient(username);
                MAPIFolder sharedCalendar = _app.Session.GetSharedDefaultFolder(teamMember, OlDefaultFolders.olFolderCalendar);
                if (sharedCalendar.DefaultMessageClass != "IPM.Appointment" || teamMember.DisplayType != 0)
                {
                    return null; //Calendar not shared.
                }
    
                string sFilter = $"[End] > '{from:g}' AND [Start] < '{to:g}' AND [Recurring] = 'No'";
                Items results = sharedCalendar.Items.Restrict(sFilter);
                for (int i = results.Count; i > 0; i--)
                {
                    appointments.Add(new AppData(results[i], username));
                }
    
                return appointments;
            }
            catch (COMException)
            {
                return null;
            }
        }
    
        public void Dispose()
        {
            _app?.Quit();
        }