2

概要

VSTO で作成された Outlook アドインがあります。アドインには、Mail.Composeリボン タイプ用の 1 つのリボン (ビジュアル デザイナー) があります。リボンタブControlIdTypeは「カスタム」に設定されています。デザイナー コード以外のアドインの唯一のコードは、次Loadのリボンのハンドラーです。this.Context.CurrentItem予期せず null を返しています。

コード

private void RibbonComposeMail_Load(object sender, RibbonUIEventArgs e)
{
    try
    {
        var inspector = this.Context as Outlook.Inspector;
        if (inspector == null)
        {
            throw new ApplicationException("Fail - Step 1");
        }

        var currentMailItem = inspector.CurrentItem as Outlook.MailItem;
        if (currentMailItem == null)
        {
            throw new ApplicationException("Fail - Step 2");
        }

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

手順

  1. 下書きメールを開きます。リボンは正常にロードされます。
  2. 受信トレイから電子メールを開きます。
  3. 同じ下書きメールを開きます。手順 2 でリボンが失敗しましたinspector.CurrentItem。null です。

ノート

  • VS2010 で作成された Outlook 2007 および 2010 アドインと、VS2012 で作成された Outlook 2010 アドインを使用して、Outlook 2007、2010、および 2013 でこれをテストしました。すべて同じように動作します。
  • 下書きメールを繰り返し開いても問題は発生しないようです。その間に Email.Read インスペクターを開く必要があります。
  • リボン タブはControlidType重要です。「カスタム」では問題が発生しますが、「Office」のデフォルト オプションでは問題は発生しません。
  • シナリオをひっくり返して、リボンの種類を に設定してもMail.Read、開く順序が [受信トレイ] > [下書き] > [受信トレイ (失敗)] と逆であれば、同じ結果になります。
  • およびオブジェクトに対する呼び出しのすべての可能な順列は、違いはありませMarshal.ReleaseComObjectん。inspectorcurrentMailItem
4

3 に答える 3

4

私自身も同じ問題を抱えていました。

Outlook 予定表の予定用のリボン バーを設計しました。各予定と共に保存したい追加のフィールドがいくつかあります (たとえば、「この会議は出張を節約しますか?」)。

なんとかできましたが、やりにくかったです。

あなたが言ったように、Ribbon1_Load関数が起動されると、ActiveInspector()は null です... では、現在の電子メール メッセージまたはカレンダーの予定に関する詳細をどのように取得するのでしょうか?

これがあなたがする必要があることです。この例はカレンダーの予定に基づいていますが、代わりに EmailItems に適応させるのは非常に簡単です。

まず、ThisAddIn.cs ファイルでいくつかの変更を行う必要があります。

public partial class ThisAddIn
{
    Outlook.Inspectors inspectors;
    public static Outlook.AppointmentItem theCurrentAppointment;

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        inspectors = this.Application.Inspectors;
        inspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
    }

ユーザーが新しい Outlook アイテムを開くか作成すると、「Inspectors_NewInspector」関数が呼び出され、その時点で、アイテムに関する詳細を取得できます

void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
     //  This function (apparently) gets kicked off whenever a user opens a new or existing item
     //  in Outlook (Calendar appointment, Email, etc).  
     //  We can intercept it, modify it's properties, before letting our Ribbon know about it's existance.
     //
     theCurrentAppointment = null;

     object item = Inspector.CurrentItem;
     if (item == null)
         return;

     if (!(item is Outlook.AppointmentItem))
         return;

     theCurrentAppointment = Inspector.CurrentItem as Outlook.AppointmentItem;
}

このコードを配置すると、Ribbon1_Load関数を調整してこの「theCurrentAppointment」変数を取得し、ユーザーが作成/変更しているカレンダーの予定に関する詳細を読み取ることができます。

private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
     //  When this function gets called, "Globals.ThisAddIn.Application.ActiveInspector()" is always NULL, so we have
     //  to fetch the selected AppointmentItem via the ThisAddIn class.

     if (ThisAddIn.theCurrentAppointment != null)
     {
         //  Our Ribbon control contains a TextBox called "tbSubject"
         tbSubject.Text = ThisAddIn.theCurrentAppointment.Subject
     }
}
于 2013-09-12T14:29:11.437 に答える
3

マイクのコメントは、動作についてもう少し興味深いことを明らかにするのに役立ちました。ステップ 1 で、RibbonComposeMail_Loadイベントが一度呼び出されます。しかし、ステップ 3 で2 回呼び出されます。手順 3 で初めてイベントが呼び出されたときthis.Context.CurrentItemは null ですが、2 回目にイベントが呼び出されたとき、プロパティは電子メールを保持します。

NewInspectorイベントのアイテム値とリボンイベントのアイテム値を比較しLoadていて気付きました。ステップ 3 での一連のイベントはRibbon_Load、 、NewInspectorRibbon_Loadです。でメール アイテムの件名にたどり着いRibbon_Loadていましたが、それがに開かれたメール、つまりステップ 2 の受信メールの件名であることに非常に驚きました。MessageBox.ShowThisAddIn.CurrentMailItem

結局のところ、解決策は、が nullのRibbon_Load場合、イベント内のすべてを無視することです。これは、正しい値が設定されて 2 番目のイベントがトリガーされようとしているからです。私の例のステップ 3 でこの奇妙な動作が見られるのに、ステップ 1 では見られないのはなぜですか? それはおそらく、Outlook オブジェクト モデルを実装した人々にとっての疑問です。this.Context.CurrentItemRibbon_Load

于 2013-09-16T02:13:45.977 に答える
0

100% 確実ではありませんが、ガベージ コレクターが this.Context をクリアしたようです。

コンテキストをプライベート フィールドに入れて、そこから現在のアイテムを取得してみてください:

private readonly Context _context = new Context(); 


private void RibbonComposeMail_Load(object sender, RibbonUIEventArgs e)
{
    try
    {
        var inspector = _context as Outlook.Inspector;
        if (inspector == null)
        {
            throw new ApplicationException("Fail - Step 1");
        }

        var currentMailItem = inspector.CurrentItem as Outlook.MailItem;
        if (currentMailItem == null)
        {
            throw new ApplicationException("Fail - Step 2");
        }

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

これで問題が解決しない場合は、通常 Outlook.Application オブジェクトを使用して currentitem を取得します。

readonly Outlook._Application _application = new Outlook.Application();

var selectionList = _application.ActiveExplorer().Selection;

foreach (Object selObject in selectionList)
{
    if (selObject is Outlook.MailItem)
    {
        var outlookMail = (selObject as Outlook.MailItem);
    }
}

または、あなたの場合のように、現在のアイテムのみが必要な場合:

var mailItem = _application.ActiveExplorer().Selection[0];
于 2013-08-27T09:11:07.410 に答える