Outlook ItemAdd事件由VSTO插件和WPF应用程序注册,触发两次。

huangapple go评论67阅读模式
英文:

Outlook ItemAdd event registered from VSTO plugin and WPF app fires twice

问题

我有两个.NET应用程序:一个用于Outlook的VSTO插件和一个WPF应用程序。这两个应用程序都使用Outlook互操作发送电子邮件,并需要对发送的电子邮件项执行某些操作。为此,两个应用程序都使用Outlook互操作,并将相同的方法注册到发送邮件文件夹的ItemAdd事件。

一些用户只使用VSTO;其他用户只使用WPF应用程序。然而,一些用户既使用VSTO又使用WPF应用程序,在这种情况下,ItemAdd事件的方法将触发两次。我尝试使用单例模式来解决这个问题(见下文),但它没有起作用。

请建议如何使其工作,以便HandleSentMail方法只触发一次,即使用户既安装了VSTO又运行了WPF应用程序。

注册事件

VSTO和WPF应用程序都使用以下代码将HandleSentMail方法附加到ItemAdd事件(在VSTO中,它放置在Ribbon1_Load方法中):

OutlookInterface.Instance.SentMailItems.ItemAdd -= new ItemsEvents_ItemAddEventHandler(MailHandler.Instance.HandleSentMail);
OutlookInterface.Instance.SentMailItems.ItemAdd += new ItemsEvents_ItemAddEventHandler(MailHandler.Instance.HandleSentMail);

OutlookInterface.cs

public sealed class OutlookInterface {
  /// <summary>
  /// 单例模式,参见
  /// https://csharpindepth.com/articles/singleton
  /// </summary>
  private static readonly Lazy<OutlookInterface> lazy = new Lazy<OutlookInterface>(() => new OutlookInterface());

  public static OutlookInterface Instance { get { return lazy.Value; } }

  public Application MailApplication { get; set; }

  public Items SentMailItems { get; set; }

  private OutlookInterface() {
    MailApplication = new Application();
    SentMailItems = MailApplication.Session.GetDefaultFolder(OlDefaultFolders.olFolderSentMail).Items;
  }
}

MailHandler.cs

public sealed class MailHandler {
  /// <summary>
  /// 单例模式,参见
  /// https://csharpindepth.com/articles/singleton
  /// </summary>
  private static readonly Lazy<WorkZoneMailHandler> lazy = new Lazy<WorkZoneMailHandler>(() => new WorkZoneMailHandler());

  public static WorkZoneMailHandler Instance {
    get {
      return lazy.Value;
    }
  }

  public async void HandleSentMail(object item) {
    ...
  }
}
英文:

I have two .NET applications: A VSTO plugin for Outlook and a WPF application. Both applications send e-mail with Outlook and need to do something to these sent e-mail items. To that end, both applications use Outlook interop and register the same method to the ItemAdd event for the sent mail folder.

Some users only use the VSTO; other users only use the WPF application. However, some users have the VSTO and also use the WPF application, and in that case, the method for the ItemAdd event is fired twice. I tried to get around this using a Singleton pattern (see below), however it is not working.

Please advise on how I can make it work, such that the HandleSentMail method is only fired once, even if the user has both the VSTO and is running the WPF application.

Registering event

Both the VSTO and the WPF application use the following code to attach a method HandleSentMail to the ItemAdd event (in the VSTO, it is placed in the Ribbon1_Load method):

OutlookInterface.Instance.SentMailItems.ItemAdd -= new ItemsEvents_ItemAddEventHandler(MailHandler.Instance.HandleSentMail);
OutlookInterface.Instance.SentMailItems.ItemAdd += new ItemsEvents_ItemAddEventHandler(MailHandler.Instance.HandleSentMail);

OutlookInterface.cs

public sealed class OutlookInterface {
  /// &lt;summary&gt;
  /// Singleton pattern, see
  /// https://csharpindepth.com/articles/singleton
  /// &lt;/summary&gt;
  private static readonly Lazy&lt;OutlookInterface&gt; lazy = new Lazy&lt;OutlookInterface&gt;(() =&gt; new OutlookInterface());

  public static OutlookInterface Instance { get { return lazy.Value; } }

  public Application MailApplication { get; set; }

  public Items SentMailItems { get; set; }

  private OutlookInterface() {
    MailApplication = new Application();
    SentMailItems = MailApplication.Session.GetDefaultFolder(OlDefaultFolders.olFolderSentMail).Items;
  }
}

MailHandler.cs

public sealed class MailHandler {
  /// &lt;summary&gt;
  /// Singleton pattern, see
  /// https://csharpindepth.com/articles/singleton
  /// &lt;/summary&gt;
  private static readonly Lazy&lt;WorkZoneMailHandler&gt; lazy = new Lazy&lt;WorkZoneMailHandler&gt;(() =&gt; new WorkZoneMailHandler());

  public static WorkZoneMailHandler Instance {
    get {
      return lazy.Value;
    }
  }

  public async void HandleSentMail(object item) {
    ...
  }
}

答案1

得分: 1

你可以选择拥有一种全局可访问的已处理消息的数据库/列表,并存储其中一种应用程序处理的消息的条目 ID,以便另一种应用程序不会再处理它;或者更好的做法是,给一种应用程序优先权,而不是另一种(例如,插件优先于独立应用程序)。你可以在 HandleSentMail 方法中使用一个具有名称的互斥体来实现这一点 - 插件可以在启动时打开互斥体(并在关闭时关闭它),但独立应用程序可以检查互斥体是否已经被打开,如果已经打开,则跳过处理:

Mutex m = new Mutex(true, "YourCustomMutex", out bool createdNew);
if (createdNew)
{
    // 应用程序尚未运行。
}
英文:

You can either have some kind of globally accessible db/list of processed messages and store the entry ids of the messages one of the two apps processed so that the other won't pick it up, or, better yet, give priority to one app over another (e.g. addin takes priority over the standalone app). You can use a named mutex for that in the HandleSentMail method - addin can open the mutex on startup (and close it on shutdown), but the standalone app can check if the mutex has already been opened, and if it was, skip processing:

Mutex m = new Mutex(true, &quot;YourCustomMutex&quot;, out bool createdNew);
if (createdNew)
{
    // The application is not already running.
}

答案2

得分: 0

以下是翻译好的部分:

"Instead of trying to find any mechanism which allows detecting the second event you need to handle events on the add-in side and use standard techniques for interprocess communications (for example, .net remoting) and connect your WPF application with your VSTO add-in instead. They are both .net applications! When you load Outlook from your WPF application your VSTO add-in is loaded as well, so you can connect to it instead of handling Outlook events. Just add a condition if the add-in is loaded don't subscribe to the events in the code.

You may find Windows Communication Foundation (WCF) helpful in that case, see Develop Service-Oriented Applications with WCF for more information."

英文:

Instead of trying to find any mechanism which allows detecting the second event you need to handle events on the add-in side and use standard techniques for interprocess communications (for example, .net remoting) and connect your WPF application with your VSTO add-in instead. They are both .net applications! When you load Outlook from your WPF application your VSTO add-in is loaded as well, so you can connect to it instead of handling Outlook events. Just add a condition if the add-in is loaded don't subscribe to the events in the code.

You may find Windows Communication Foundation (WCF) helpful in that case, see Develop Service-Oriented Applications with WCF for more information.

huangapple
  • 本文由 发表于 2023年7月6日 20:58:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76629108.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定