共用方式為


Updating NoReplyAll for Outlook 2013

As I mentioned in an earlier post, Outlook 2013 brings a few new features which I need to integrate with in NoReplyAll., the main one being ribbon changes when inline responses are used.

The What's new for Outlook 2013 developers article describes programmatic access to inline response objects. An inline response is indicated by the InlineResponse event so it's pretty obvious that I need to handle that to update ribbon controls. Because I need my add-in to work with earlier versions of Outlook, I can't unconditionally reference the event; the Outlook 2010 VSTO interfaces obviously don't include any information about the event either. Rather than update to a newer VSTO (to be honest, I've not actually looked to see what exists, instead I'm just updating the current project with the same version of .NET framework and associated bits and pieces), I thought I'd see what I could do with reflection... (Actually, my first thought was to use dynamic, but that doesn't handle events, I think.)

         private void AddInlineResponseHandler()
        {
            var einfo = this.explorer.GetType().GetEvent("InlineResponse", BindingFlags.Public | BindingFlags.Instance);
            if (einfo != null)
            {
                var handler = Delegate.CreateDelegate(einfo.EventHandlerType, this, this.GetType().GetMethod("OnInlineResponse", BindingFlags.NonPublic | BindingFlags.Instance));
                einfo.AddEventHandler(this.explorer, handler);
            }
        }

The above uses reflection to locate the event and attach the handler (this.explorer is the active explorer object, and OnInlineResponse is my handler). The handler itself doesn't do a lot, just invalidates the explorer ribbon, causing it to refresh its button states.

When an inline response is on the screen, there are some new controls on the explorer ribbon, specifically the Message tab. Besides that, the remainder of the explorer ribbon is pretty much the same. As I already have some NoReply-related controls on the explorer ribbon, I thought I'd repurpose those when handling an inline response, and I can easily use the event handler above to switch into that mode. Unfortunately, I haven't discovered a means of tracking exit from inline response mode... The inline response "goes away" in three ways: the message can be sent, the response can be discarded, or the response can be popped out to an external window. The first of those can be detected via a Send event, but I haven't found a way to detect the others. So: I can detect entry to inline response mode to be able to switch my existing explorer ribbon controls, but I haven't got a way to switch them back.

Instead I chose to add some more controls to the Message tab - these controls indicate the state of the message being composed, while the previously existing controls show the state of the message being replied to. I think I need to come up with something less potentially confusing to the end user, but this will do for now. The controls are defined in a ContextualTabs section of the backstage and explorer ribbon XML:

  <contextualTabs>
  <tabSet idMso='TabComposeTools'>
   <tab idMso='TabMessage'>
    <group id='grpIReply' label='Disable'>
     <toggleButton id='btnINoReplyAll' tag='2:Reply to All'
                   size='large' getImage='Button_GetLargeImage'
                   getPressed='ItemIButton_IsPressed' onAction='ItemIButton_Click'
                   screentip='No Reply All' supertip='Prevent recipients within the same organisation from replying to all'
                   label='Reply All' />
     <toggleButton id='btnINoReply' tag='1:Reply'
                   size='normal' getImage='Button_GetSmallImage'
                   getPressed='ItemIButton_IsPressed' onAction='ItemIButton_Click'
                   screentip='No Reply' supertip='Prevent recipients within the same organisation from replying'
                   label='Reply' />
     <toggleButton id='btnINoForward' tag='3:Forward'
                   size='normal' getImage='Button_GetSmallImage'
                   getPressed='ItemIButton_IsPressed' onAction='ItemIButton_Click'
                   screentip='No Forward' supertip='Prevent recipients within the same organisation from forwarding the invitation'
                   label='Forward' />
    </group>
   </tab>
  </tabSet>
 </contextualTabs>

The handler methods are a little different to ones written previously. The handler is passed a reference to the control, via which I've found the currently viewed message using the explorer's current selection: this refers to the message being responded to (as evidenced by my prior explorer ribbon controls). Instead, I need to make use of another new feature to get hold of the message being composed, the ActiveInlineResponse property. Once I've got the item, the processing is just the same as described in previous posts.

Yet another wrinkle to deal with is that Outlook 2010 (and earlier) know nothing about this TabMessage and will complain if I use the XML above (albeit fairly quietly - you only see UI errors if you ask for them in Outlook's advanced options page). The "fix" is yet another version check to choose this new XML or the old copy without the contextual tabs section.

And that's it. I've got inline response ribbon support now - but not so fast! When the user clicks reply, the inline response ribbon controls appear, and my InlineResponse event handler kicks in to cause the controls to update their state correctly. When the user dismisses the inline response (by whichever of the three methods mentioned above), the new controls vanish without me having to do anything clever. Unfortunately, however, the buttons don't actually do anything... According to the ActiveInlineResponse page, I should be able to inspect and manipulate the no-reply, etc. actions associated with the inline response - it turns out that that's not actually true: it is not possible to access MailItem.Actions at all for an inline response. (I believe that the MSDN page will be updated soon, with the correct information.) The upshot of this is that while I can indeed correctly display and react to buttons specific to inline responses, I can't use them to manipulate reply-all, etc.

So, no inline response support for the NoReplyAll Add-in, alas, unless I can come up with some way to capture button states and attach them to the message when it's being sent (assuming I can manipulate Actions there)...