“阅读” Outlook 2007 VSTO VB.NET 中的 Mailitem 事件
好吧,这有点棘手...
我正在使用 VS 2010 和 VSTO 以及 VB.NET 为 MS Outlook 2007 编写一个加载项。我的目标是提示用户打印从某些电子邮件地址收到的电子邮件。 (这可以通过一个简单的 MsgBox 来完成。)
具体来说,我希望用户在阅读完电子邮件后得到提示。我的想法是,它的工作方式应该类似于 Outlook 中的“已读回执”功能。 (你知道,那些烦人的事情...“发件人已要求您提供收据,表明您已阅读这封电子邮件等等”)
因此,用户阅读电子邮件,然后当他们关闭电子邮件时检查器(或者如果位于资源管理器视图中,则将焦点更改为其他项目)会弹出消息框。我注意到这与电子邮件变为“已读”的时间相匹配。
我已经在 Google、MSDN 和教程网站上追寻这个问题几天了,这是我发现的:
第 1 轮: Mailitem 对象具有 UnRead 属性,并且还具有 PropertyChange 事件。我可以对收件箱中的每个邮件项目使用 AddHandler for PropertyChange,将它们绑定到单个子例程中,该子例程检查 PropertyChange 事件的参数以确保它是未读的。似乎相当可行,只是 PropertyChange 不传递调用对象的身份,因此我无法知道收件箱中的哪些电子邮件刚刚丢失了“未读”状态。
事实上,似乎没有一个 Mailitem 事件传递它们的身份,可能是因为有人(我猜是 MS)假设您首先有一个指向 Mailitem 对象的直接指针。所以这条路似乎行不通。
第二轮: 我可以将收件箱中的所有邮件项目抓取到一个集合中,然后将它们限制为仅未读邮件项目。
Dim inbox As Outlook.MAPIFolder = Nothing
Dim WithEvents unreadItems As Outlook.Items
inbox = Me.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
unreadItems = inbox.Items.Restrict("[Unread]=true")
由于 unreadItems 因事件而变暗,我可以编写一个 Sub 来处理 unreadItems.ItemRemove,这会很好地工作。但 ItemRemove 事件没有对象参数!哎哟!
第三轮: 假设我执行相反的操作:获取收件箱内容并限制为 [Unread]=false,然后使用 .ItemAdd 事件。这在一定程度上是有效的,只是理论上,每当用户从任何文件夹将“[Unread]=false”项目转储到收件箱中时,而不仅仅是收件箱中从“未读”组更改为“已读”组时,它都会调用。所以,除非我在这里误解了什么,否则也不是一个选择。
第四轮: 现在,我还想到了简单地调暗收件箱项目集合 WithEvents 并关闭 .ItemChange 事件,但此事件并没有真正指定对象发生了什么变化,所以没有骰子。
最后,我对此感到非常困惑。我已经快要放弃我的目标了。一个蹩脚的替代方案是当用户收到来自指定地址之一的电子邮件时提醒用户(因为我相信 Application.NewMail 事件不会给我带来任何麻烦)。但是,然后,我将不得不简单地提醒用户 - 我不会提示他们打印他们甚至还没有阅读的电子邮件。
这种选择是不可取的,我想我会提出我的问题以供检查和建议。
-马特
P.S.我以前使用 Objective-C 制作 iPad 应用程序,我自己构建了大部分对象层次结构……必须处理具有此类限制的 COM 对象,这很奇怪。
Okay, this is a bit of a tricky one...
I am programming an add-in for MS Outlook 2007, using VS 2010 and VSTO, and VB.NET. My goal is to prompt the user to print off emails that they receive from certain email addresses. (This would be done with a simple MsgBox.)
Specifically, I would like the prompt the user when they are done reading the email. My concept is that it should work similarly to the "Read Receipt" functionality in Outlook. (You know, those annoying things..."The sender has requested a receipt that you have read this email blah blah")
So, the user reads the email, and then when they go to close the Inspector (or change focus to a different item if they are in Explorer view) the MsgBox pops up. I have noticed that the timing on this matches when the email becomes "read".
I have been chasing this across Google and MSDN and tutorial websites for a few days, here's what I've found:
Round 1:
The Mailitem object has an UnRead property, and it also has a PropertyChange event. I can use AddHandler for PropertyChange on every Mailitem in the Inbox, tying them into a single Subroutine that checks the argument of the PropertyChange event to make sure it's UnRead. Seems fairly workable, except that PropertyChange doesn't pass the calling object's identity, so I have no way of knowing what email in the Inbox just lost "unread" status.
In fact, none of the Mailitem events seem to pass their identity, probably because someone (MS I guess) assumes that you have a direct pointer to the Mailitem object in the first place. So this route doesn't seem to work.
Round 2:
I can grab all of the Mailitems in the Inbox into a collection, then restrict them to just the Unread ones.
Dim inbox As Outlook.MAPIFolder = Nothing
Dim WithEvents unreadItems As Outlook.Items
inbox = Me.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
unreadItems = inbox.Items.Restrict("[Unread]=true")
Since unreadItems was Dimmed WithEvents, I could write a Sub to Handle unreadItems.ItemRemove, which would work fine. But the ItemRemove event has no object argument! Doh!
Round 3:
Let's say I do the opposite: I get the inbox contents and restrict to [Unread]=false, then use the .ItemAdd event. This would work to a degree, except that it would theoretically call whenever an "[Unread]=false" item was dumped into the Inbox by the user from any folder, not just a change from the Unread to Read group within the Inbox. So, unless I'm misunderstanding something here, also not an option.
Round 4:
Now, something I also thought of was simply Dimming the Inbox items collection WithEvents and going off the .ItemChange event, but this event doesn't really specify what changed about the object, so no dice.
In closing, I'm pretty darn stumped with this. I am very close to backing down from my goal. A lame alternative is to alert the user when they receive an email from one of the designated addresses (because I believe the Application.NewMail event won't give me any hassle). But then, I will have to simply alert the user--I won't prompt them to print an email they haven't even read yet.
This alternative is undesirable and I figured that I would present my problem for inspection and suggestion.
-Matt
P.S. I'm coming from making iPad apps with Objective-C, where I'm building most of the object hierarchy myself...it's weird to have to deal with COM objects that have such limitations.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不太确定您希望 UI 的行为方式如何,因为不太清楚用户何时阅读完电子邮件。一种看待它的方法是,当他们查看完邮件时,他们就完成了,这意味着检查器窗口已经显示了邮件,并且用户正在切换到另一封邮件。要了解这一点,您可能最好从检查员那里观看事件,而不是邮件。
另一种看待它的方式是,只要邮件被标记为已读,就会被阅读。请注意,用户实际上可能会关闭将项目标记为自动已读的选项!这可以在“工具”->“选项”->“其他”->“阅读”窗格中完成,如下所示:
此外,用户可以选择项目并将其标记为手动阅读,因此您需要考虑在这种情况下您想要做什么。
如果您想观察 MailItem 的“read”属性的变化,那么您在第 1 轮中就非常接近了。您需要添加的是,您不应该将所有处理程序绑定到单个对象中的单个子例程实例。相反,您可以创建自己的类,如下所示(C# 代码):
然后您需要创建 ItemWatcher 类的集合并将它们设置为监视您的电子邮件。
请注意,当新邮件到达或旧邮件被删除/移动时,您还需要监视需要从监视项目集合中添加/删除的项目。
I'm not quite sure how you want your UI to behave, because it's not quite clear when the user is done reading their email. One way to look at it is that they are done when they have looked at it, meaning that the inspector window has shown the mail and the user is switching to another one. To catch that, you would probably be best off watching events from the inspector, not the mail items.
The other way to look at it is that a mail is read whenever it is marked as Read. Be aware that the user may actually turn off the option to mark items as read automatically! This can be done in Tools->Options->Other->Reading pane, like this:
Also, the user may select items and mark them as read manually, so you need to think about what you want do in that case.
If you want to watch for the change in "read" property of the MailItem, you are very close in round 1. The thing you need to add is that you shouldn't tie all of your handlers to a single subroutine in a single object instance. Instead, you can create your own class, something like this (C# code):
Then you need to create a collection of your ItemWatcher classes and set them to watch your emails.
Note that you will also need to watch for items you need to add/remove from your collection of watched items, when a new mail arrives or an old mail is deleted/moved.