2013년 4월 29일 월요일

How to show unique\distinct values in a data view web part


To remove the duplicate site names from the view I had replace the default web part using a  Data View web part and then modify the Xslt Rows variable to query only unique site names using the Site ID field value.  Figure 2 will show the Xpath code that I am using to remove duplicate site names from the view. This will remove the duplicate site names and only show unique site names within the view. Figure 3 shows the view after I’ve updated the data view web part.
Figure 2
Figure 3

2013년 4월 18일 목요일

프로그램 추가 제거 체크

프로그램 추가 제거 체크

http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/94c2f14d-c45e-4b55-9ba0-eb091bac1035/


The solution is to search for 3 places in registry:
1. SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall inside CurrentUser
2. SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall inside LocalMachine
3. SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall in LocalMachine



public static bool IsApplictionInstalled(string p_name)
{
    string displayName;
    RegistryKey key;

    // search in: CurrentUser
    key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
    foreach (String keyName in key.GetSubKeyNames())
    {
        RegistryKey subkey = key.OpenSubKey(keyName);
        displayName = subkey.GetValue("DisplayName") as string;
        if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
        {
            return true;
        }
    }

    // search in: LocalMachine_32
    key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
    foreach (String keyName in key.GetSubKeyNames())
    {
        RegistryKey subkey = key.OpenSubKey(keyName);
        displayName = subkey.GetValue("DisplayName") as string;
        if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
        {
            return true;
        }
    }

    // search in: LocalMachine_64
    key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
    foreach (String keyName in key.GetSubKeyNames())
    {
        RegistryKey subkey = key.OpenSubKey(keyName);
        displayName = subkey.GetValue("DisplayName") as string;
        if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
        {
            return true;
        }
    }

    // NOT FOUND
    return false;
}

2013년 4월 17일 수요일

프로그램 추가 제거


프로그램 추가 제거

msiexec /uninstall SetupfilePath\SetupFileName.msi

2013년 4월 7일 일요일

2013년 4월 2일 화요일

sharepoint email


using System;
using System.Security.Permissions;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;

//Code courtesy of @timferro, @dannyjessee, MSDN, and the internet
namespace SharePointProject1.EventReceiver1
{
    /// <summary>
    /// List Item Events
    /// </summary>
    public class EventReceiver1 : SPItemEventReceiver
    {
       /// <summary>
       /// An item is being added.
       /// </summary>
       public override void ItemAdding(SPItemEventProperties properties)
       {
           base.ItemAdding(properties);
       }

       /// <summary>
       /// An item is being updated.
       /// </summary>
       public override void ItemUpdating(SPItemEventProperties properties)
       {
           base.ItemUpdating(properties);
           if ((string)properties.ListItem["Status"] != (string)properties.AfterProperties["Status"])
           {
               properties.AfterProperties["Notes"] = "Status Change";
           }
       }

       /// <summary>
       /// An item is being deleted.
       /// </summary>
       public override void ItemDeleting(SPItemEventProperties properties)
       {
           base.ItemDeleting(properties);
           //Get user object
           SPUser user = properties.Web.SiteUsers.GetByID(properties.CurrentUserId);
           //If the user is not a Site Collection Admin, don't delete the item
           if (!user.IsSiteAdmin)
           {
               //Cancel the request with an error and set the error message
               properties.Status = SPEventReceiverStatus.CancelWithError;
               properties.ErrorMessage = "Only Site Collection Administrators can delete items from this list!";
           }
           
       }

       /// <summary>
       /// An attachment is being added to the item.
       /// </summary>
       public override void ItemAttachmentAdding(SPItemEventProperties properties)
       {
           base.ItemAttachmentAdding(properties);
       }

       /// <summary>
       /// An item was added.
       /// </summary>
       public override void ItemAdded(SPItemEventProperties properties)
       {
           base.ItemAdded(properties);
           //Get the list item that was added
           SPListItem item = properties.ListItem;

           //Set the Notes field with ItemAdded
           item["Notes"] = "ItemAdded";

           //Get a reference to the TestDocument document library
           SPList testDoc = properties.Web.Lists["TestDocument"];

           //Create a new folder in the document library
           SPListItem folder = testDoc.Folders.Add("", SPFileSystemObjectType.Folder, item.Title);
           folder.Update();

           //Get the document library name and folder url
           string[] splitFolderUrl = folder.Url.Split('/');

           //Encode the url string
           string folderUrlEncode = SPHttpUtility.UrlKeyValueEncode("/" + folder.Url);

           //Update the list item with the link
           item["Documents"] = properties.WebUrl + "/" + splitFolderUrl[0].ToString() + "/Forms/AllItems.aspx?RootFolder=" + folderUrlEncode + ", Click Me";
           
           //Disable event firing in this thread to avoid loops
           this.EventFiringEnabled = false;
           //Update the list item
           item.Update();
           //Reenable event firing
           this.EventFiringEnabled = true;
       }

       /// <summary>
       /// An item was updated.
       /// </summary>
       public override void ItemUpdated(SPItemEventProperties properties)
       {
           base.ItemUpdated(properties);
           //Get the updated list item object
           SPListItem item = properties.ListItem;
           //Set the Notes field to ItemUpdated
           item["Notes"] += " - ItemUpdated";

           //If the SetAlert checkbox is checked
           if ((Boolean)item["SetAlert"])
           {
               //Set it back to false
               item["SetAlert"] = false;
               //Get the current user's object
               SPUser user = properties.Web.SiteUsers.GetByID(properties.CurrentUserId);
               //Create a new user alert
               SPAlert alert = user.Alerts.Add();
               alert.Title = item.Title;
               alert.AlertType = SPAlertType.Item;
               alert.AlertFrequency = SPAlertFrequency.Immediate;
               alert.EventType = SPEventType.All;
               alert.Item = item;
               alert.Update(false);
           }

           //If the SendEmail checkbox is checked
           if ((Boolean)item["SendEmail"])
           {
               //Set it back to false
               item["SendEmail"] = false;
               //Send an email using SPUtility.SendEmail
               SPUtility.SendEmail(properties.Web, false, false, "timothy.ferro@gmail.com", "FEDSPUG Test Email", "TEST");
           }

           //Disable event firing in this thread to avoid loops
           this.EventFiringEnabled = false;
           //Update the list item
           item.Update();
           //Reenable event firing
           this.EventFiringEnabled = true;
       }

       /// <summary>
       /// An item was deleted.
       /// </summary>
       public override void ItemDeleted(SPItemEventProperties properties)
       {
           base.ItemDeleted(properties);
       }

       /// <summary>
       /// An attachment was added to the item.
       /// </summary>
       public override void ItemAttachmentAdded(SPItemEventProperties properties)
       {
           base.ItemAttachmentAdded(properties);
       }


    }
}

powershell 솔루션 업로드

powershell 솔루션 업로드 배포하기


Add-SPSolution "C:\Deploy\EventRec_SendMail.wsp"
Install-SPSolution -Identity EventRec_SendMail.wsp -GACDeployment -webapplication "http://ddd.aa.co.kr"

Update-SPSolution -Identity EventRec_SendMail.wsp -LiteralPath "C:\Deploy\EventRec_SendMail.wsp" -GacDeployment
Uninstall-SPSolution -Identity EventRec_SendMail.wsp
Remove-SPSolution -Identity EventRec_SendMail.wsp

2013년 4월 1일 월요일

EventContext context = properties.Context;


EventContext context = properties.Context;


http://code.lamsfoundation.org/fisheye/browse/~raw,r=1.1/lams/LamsSharePointIntegration/LamsSharePointIntegration/Src/LAMSLessonListEventHandler.cs



/****************************************************************
 * Copyright (C) 2008 LAMS Foundation (http://lamsfoundation.org)
 * =============================================================
 * License Information: http://lamsfoundation.org/licensing/lams/2.0/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2.0 
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 * 
 * http://www.gnu.org/licenses/gpl.txt
 * ****************************************************************
 */

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace LamsSharePointIntegration
{
    /// <summary>
    /// This class handles events to do with the site's LAMS lesson table
    /// </summary>
    class LAMSLessonListEventHandler : SPItemEventReceiver
    {
        private string FormatCompanyName(string value)
        {
            return value.ToUpper();
        }

        public override void ItemAdding(SPItemEventProperties properties)
        {
            // Validation handled by SharePoint
        }

        /// <summary>
        /// Handles the event when a new lesson is added to the LAMS lesson table for the site
        /// </summary>
        /// <param name="properties">Properties of the item to be added</param>
        public override void ItemAdded(SPItemEventProperties properties)
        {
            // Get the site context information
            SPEventContext context = properties.Context;
            SPSite site = new SPSite(properties.SiteId);
            SPWeb siteWeb = site.OpenWeb(properties.RelativeWebUrl);
            SPUser user = siteWeb.CurrentUser;
            DisableEventFiring();

            // Get the title for the lesson, not null
            string title = properties.ListItem["Title"].ToString();
            
            // Get the description for the leson
            string description = "";
            if (properties.ListItem["Description"] != null)
            {
                description = properties.ListItem["Description"].ToString();
            }

            // Get the sequence id for the lesson, not null
            string sequenceId = properties.ListItem["SequenceID"].ToString();
                        
            // The lesson id of the started lesson, if successful
            string lessonId;
            try
            {
                lessonId = LAMSSecurityUtil.startLesson(user, siteWeb, sequenceId, title, description, "start");
            }
            catch (System.Net.WebException e)
            {
                properties.ErrorMessage = "Request to LAMS server to start lesson failed. Please Contact System Administrator";
                properties.Cancel = true;
                properties.Status = SPEventReceiverStatus.CancelWithError;
                properties.ListItem.Delete();
                return;
            }

            // Set the LessonID param for the item and the start and end date to null
            properties.ListItem["LessonID"] = lessonId;
            properties.ListItem["Start Date"] = null; 
            properties.ListItem["End Date"] = null; 
            
            properties.ListItem.Update();
            EnableEventFiring();
        }
    }
}

웹파트 배포시 에러 "컴퓨터의 SPUserCodeV4 서비스를 시작할 수



웹파트 배포시 에러 "컴퓨터의 SPUserCodeV4 서비스를 시작할 수

출처 : http://sharepoint.tistory.com/226

VS 2010 을 이용해서 개발한 쉐어포인트 모듈(샌드박스 모듈)을 배포하는데 에러가 발생합니다

컴퓨터의 SPUserCodeV4 서비스를 시작할 수 없습니다
라고 메세지가 뜨면서 에러가 발생하는데, 해결법은 이렇습니다.

중앙관리 사이트에 접속하여 시스템설정->서버의 서비스 관리로 이동합니다.

샌드박스 관련 서비스가 꺼져 있는 것을 볼 수 있습니다.

“시작” 을 눌러 서비스를 시작시킵니다.
 

해결완료 !!

sharepoint mail send


Send Email from SharePoint - SPUtility.SendEmail


Sending email is a key function of enterprises solutions. Inside SharePoint collaboration environment you always need to send email from within SharePoint. For this purpose you can use SPUtility class SendEmail method.

 
Did you ever need to send an email out, from your SharePoint custom web application? When you have such a task, perhaps the first idea that you have is to use System.Net.Mailnamespace. However, this requires that your application maintains a setting for the SMTP server, reply address and etc.
If you want the task of storing this configuration to SharePoint (and its Administrator) and instead, just focus on sending out the actual email then the solution is the Microsoft.SharePoint.Utilities.SPUtilityclass! It has the very convenient method 'SendEmail'. This is basically SharePoint's native functionality for email delivery.

The first thing you (or the SharePoint Administrator) need to do is setup the Outgoing email SMTP server. Open Central Admin àSystem SettingsàConfigure Outgoing Email
There, you need to set the Outbound SMTP server, From address and Reply-to address.
Now, you actually send email from your code as follows:
First, it is always a good idea to check if the email server is set:
bool blnIsEmailServerSet = SPUtility.IsEmailServerSet(web);

If this returns false, you should not bother trying to send the email. Instead, show an error message or notify the SharePoint administrator, to check the settings of the server. If it returns true, you are good to go:
SPWeb web = SPContext.Current.Web;
bool appendHtmlTag = false;
bool htmlEncode = false;
string toAddress = "test@example.com";
string subject = "Subject";
string message = "Message text";
bool result = SPUtility.SendEmail(web, appendHtmlTag, htmlEncode, toAddress, subject, message);

In some cases, you may need to run this code with elevated privileges:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
bool result = SPUtility.SendEmail(web, appendHtmlTag, htmlEncode, toAddress, subject, message);
});
SendEmail method returns a boolean, indicating if sending the email was successful or not.

As you can see that sending email using SPUtility is straightforward, please also note the following considerations
1.   No attachment allowed
2.   Message body size cannot exceed 2048 characters.
3.   The from address will be the “Outbound Sender Address” configured in the central admin.





http://emailfromsharepoint.blogspot.kr/2012/04/send-email-from-sharepoint.html
http://www.mindfiresolutions.com/Send-Email-in-Sharepoint-using-SPUtilitySendEmail-using-HTML-tags-1271.php

2013년 3월 20일 수요일

c# - Claim auth from ADFS



c# - Claim auth from ADFS

jwillmer release 2013-03-21 04:29:01 View:1

I try to connect to a SharePoint Online instance via a WPF-Application. I have found this article[1] that discribes a possible solution but the problem is that the specific instance has a Active Directory Federation Services (ADFS) infront and I don't know how to get the auth-token. (I can't create a certificate for my application to authentificate against the adfs.)
Anyone who have already done this and can support me with some code snippets?
[1] http://www.wictorwilen.se/Post/How-to-do-active-authentication-to-Office-365-and-SharePoint-Online.aspx
------ Solutions --------------------------------------------------------
I've played with Fiddler. Basically the flow goes like this:
  • Get a SAML token from ADFS
  • Post it to https://login.microsoftonline.com/login.srf (body should be wa=wsignin1.0, wresult=<requestsecuritytokenresponse>…token…</rstr> and wctx=MEST=0&LoginOptions=2&wa=wsignin1%2E0&rpsnv=2&ct=1343219880&rver=6%2E1%2E6206%2E0&wp=MBI&wreply=https%3A%2F%2Fspirit365%2Esharepoint%2Ecom%2F%5Fforms%2Fdefault%2Easpx&id=500046&cbcxt=mai&wlidp=1&guest=1&vv=910&mkt=EN-US&lc=1033&bk=1343219930
  • Capture the input hidden named "t" from the Form
  • POST that "t" to /_layouts/Authenticate.aspx. That should give you the FedAuth and rtFa cookie.
From that point this is the same as the code here: http://www.wictorwilen.se/Post/How-to-do-active-authentication-to-Office-365-and-SharePoint-Online.aspx
------ Solutions --------------------------------------------------------
I have found the solution and made a post about it. I also put it on github. You can find my blog post along with the github link at my blog:http://jwillmer.de/blog/2013/01/04/sharepoint-online-with-adfs-authentication/
I hope this helps you as much as it helped me :-)

2013년 3월 11일 월요일

Treeview Recursive trawl using the SP Client Object Model

Recursive trawl using the SP Client Object Model


Here’s a simple example of SP2010’s managed Client Object Model being used to build up a TreeView of subsites and lists, for a given site. 

I’m using WinForms just to show the concept, if you’d like to recreate it, simply create a form and insert a TreeView control (called tv1), and a Label (called label1). Don’t forget to add a reference to Microsoft.SharePoint.Client as well.

Screen Shot 2011-09-13 at 2.43.16 PM

Optionally comment out the “Short Version” and uncomment the Long - This additional code goes an extra level, i.e. it iterates through the items of each list. Bear in mind this will slow down considerably, and there is also the 5000 row List Threshold limit to take into account. 

I had expected File Size to be a property in the COM (let me know if it is!) but I just couldn’t find anything related. This means we’re still stuck with dealing with CAML / Internal Names, etc. when it comes to bringing these back, e.g. File_x0020_Size :(

Check out MSDN’s Using the SharePoint Foundation 2010 Managed Client Object Model as a good starting point. The way Linq is used to ‘queue up’ only the relevant list properties we’re after, and filter the list collection to ignore hidden lists is pretty neat, makes for very simple / brief code.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using Microsoft.SharePoint.Client;

namespace WindowsFormsApplication1
{
    public partial class Form1 : System.Windows.Forms.Form
    {
        private SPItems items = new SPItems();

        public Form1()
        {
            InitializeComponent();

            items.ItemAdded += new SPItems.OnItemAdded(items_ItemAdded);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            new Thread(() =>
            {
                using (ClientContext clientContext = new ClientContext("http://mysite”))
                {
                    clientContext.AuthenticationMode = ClientAuthenticationMode.Default;
                    clientContext.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

                    var web = clientContext.Web;

                    ProcessWeb(clientContext, web, new Guid());
                }

                tv1.Invoke(new Action(() =>
                {
                    tv1.Nodes.Add(items.getTreeNodeCollection());
                    tv1.Nodes[0].Text = "Site Structure";
                    tv1.SelectedNode = tv1.Nodes[0];
                    tv1.ShowNodeToolTips = true;
                    tv1.ExpandAll();
                }));

            }).Start();
        }

        protected void items_ItemAdded(object sender, SPItem i)
        {
            label1.Invoke(new Action(() => label1.Text = i.Title));
        }

        private void ProcessWeb(ClientContext c, Web web, Guid parentID)
        {            
            c.Load(web);
            c.Load(web.Lists, lists => lists.Include(l => l.Title, 
                                                    l => l.Id, 
                                                    l => l.DefaultViewUrl,
                                                    l => l.ParentWebUrl).Where(l => !l.Hidden));
            c.Load(web.Webs);
            c.ExecuteQuery();

            items.AddItem(new SPItem() { ID = web.Id, 
                                         ParentID = parentID, 
                                         Title = web.ServerRelativeUrl });

            foreach (List l in web.Lists)
            {
                /* SHORT VERSION */

                items.AddItem(new SPItem()
                {
                    ID = l.Id,
                    ParentID = web.Id,
                    Title = l.Title
                });

                /* END SHORT VERSION  */
                
                /* LONG VERSION - Iterates through every listitem to get file size */

                //var cml = new CamlQuery() { ViewXml = @"<View><ViewFields><FieldRef Name='File_x0020_Size' /></ViewFields><Query></Query></View>" };
                //var lic = l.GetItems(cml);

                //try
                //{
                //    c.Load(lic);
                //    c.ExecuteQuery();

                //    long totalSize = 0;
                //    long totalItems = 0;

                //    foreach (ListItem li in lic)
                //    {
                //        if (li.FieldValues.Keys.Contains("File_x0020_Size"))
                //        {
                //            long size = 0;

                //            if (long.TryParse(li.FieldValues["File_x0020_Size"].ToString(), out size))
                //                totalSize += size;
                //        }

                //        totalItems++;
                //    }

                //    items.AddItem(new SPItem()
                //    {
                //        ID = l.Id,
                //        ParentID = web.Id,
                //        Title = l.Title,
                //        ItemCount = totalItems,
                //        ItemSizeBytes = totalSize
                //    });
                //}
                //catch (Exception exc)
                //{
                //    Debug.WriteLine("EXCEPTION: " + exc.Message);
                //}

                /* END LONG VERSION - Iterates through every listitem to get file size */
            }

            foreach (Web sub in web.Webs)
            {
                try
                {
                    ProcessWeb(c, sub, web.Id);
                }
                catch (Exception exc)
                {
                    Debug.WriteLine("EXCEPTION: " + exc.Message);
                }
            }
        }
    }

    public class SPItems : List<SPItem>
    {
        public delegate void OnItemAdded(object sender, SPItem i);
        public event OnItemAdded ItemAdded;

        public void AddItem(SPItem item)
        {
            this.Add(item);
            ItemAdded(this, item);
        }

        public TreeNode getTreeNodeCollection()
        {
            var n = new TreeNode();
            
            foreach (SPItem o in this)
            {
                if (o.ParentID == new Guid())
                    n.Nodes.Add(getNode(o));
                else
                {
                    var found = n.Nodes.Find(o.ParentID.ToString(), true);

                    if (found.Length > 0)
                        found[0].Nodes.Add(getNode(o));
                }
            }

            return n;
        }

        private TreeNode getNode(SPItem o)
        {
            return new TreeNode(o.Title)
            {
                Name = o.ID.ToString(),
                ToolTipText = "ITEM COUNT = " + o.ItemCount + Environment.NewLine + "ITEM SIZE = " + o.ItemSizeBytes
            };
        }
    }

    public class SPItem
    {
        public Guid ID { get; set; }
        public Guid ParentID { get; set; }
        public string Title { get; set; }
        public long? ItemCount { get; set; }
        public long? ItemSizeBytes { get; set; }
    }
}

How to get SubSites using client object model





How to get SubSites using client object model 




Try this code to get list of all sub sites
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Utilities;

private static void GetAllSubSites()
{
ClientContext clientContext = new ClientContext(“http://{yoursiteurl}/“);
Web oWebsite = clientContext.Web;
clientContext.Load(oWebsite,
website => website.Webs,
website => website.Title
);
clientContext.ExecuteQuery();
Console.WriteLine(“Available sites Count: ” + oWebsite.Webs.Count);
for (int i = 0; i != oWebsite.Webs.Count; )
{
Console.WriteLine(“Site Title: “+ oWebsite.Webs[i].Title);
}
}

My SharePoint Blog 
http://dhireny.blogspot.com 

2013년 3월 5일 화요일

vsto outlook contextMenu idMso



http://msdn.microsoft.com/en-us/library/ee692172.aspx#OfficeOLExtendingUI_ContextMenuforaMailItem

http://msdn.microsoft.com/ko-kr/library/dd554969.aspx


Sample Add-In

This article has an accompanying sample add-in named RibbonXOutlook14AddinCS. It uses Microsoft Visual C# and requires Microsoft Visual Studio 2008 Service Pack 1 and Outlook 2010.

Overview

The sample add-in demonstrates how to customize the ribbons, menus, context menus, and Backstage view in Outlook 2010. Developed in Visual Studio 2008 Tools for Office, the add-in adds ribbon controls, a custom menu, context menu items, and Backstage view controls, and then displays a message box when the user clicks the control or menu item. The add-in provides a visual element for every entry point in the Outlook 2010 UI that you can customize by using Fluent UI extensibility.
The sample add-in has some additional features that illustrate how to manage certain problem areas in the Outlook 2010 UI. For example, suppose that you want to show a custom group in the ribbon for received e-mail items only. The sample add-in displays the custom ribbon tab only when the selected item in the Outlook explorer is a received mail item or when the received mail item is displayed in an inspector. Although that might seem to be a trivial task at first, it is actually a complex problem because Outlook can display multiple explorer or inspector windows, and your code must be able to respond appropriately. For example, in two open explorer windows, you might have to hide the custom tab in the window that has a meeting selected, but display the custom tab in the window that has a received mail item selected. Once you understand how the sample add-in works, you can use the wrapper classes from the sample to build your own solution that can coordinate the display of your command UI in multiple Outlook windows.

Installation Instructions

To download the sample code installation package
  1. Download the OL2010ExtendingtheUserInterface_CS.zip file from Outlook 2010: Extending the User Interface in the MSDN Samples Gallery.
  2. Extract the .zip file into the folder of your choice. In Windows Vista, the default path for Visual Studio 2008 Tools for Office projects is C:\Users\user\Documents\Visual Studio 2008\Projects.
To run the Outlook Ribbon extensibility sample
  1. Close Outlook 2010.
  2. In the folder where you extracted the RibbonXOutlook14AddinCS.zip file, open the RibbonXOutlook14AddinCS solution.
  3. On the Build menu, click Build RibbonXOutlook14AddinCS.
  4. Start Outlook 2010 to start the add-in in run mode, or press F5 to start the add-in in debug mode. If Outlook does not start in debug mode, complete the following procedure.
To start Outlook in debug mode
  1. In Solution Explorer, select RibbonXOutlook14AddinCS.
  2. On the Project menu, select RibbonXOutlook14AddinCS Properties, and then click the Debug tab.
  3. Under Start Action, select the Start External Program option, and then click Browse.
  4. In the [Drive:]\Program Files\Microsoft Office\Office14 folder, select Outlook.exe.
  5. Press F5 to start the add-in in debug mode.

Code Walkthrough

The Outlook14RibbonXAddinCS solution is built with Microsoft Visual Studio 2008 Service Pack 1. It uses manual authoring of XML markup files instead of the ribbon designer that is provided with Visual Studio Tools for Office. The most important architectural feature is the use of wrapper classes (OutlookExplorer.cs for explorers andOutlookInspector.cs for inspectors) to handle multiple Outlook windows. The wrapper classes are implemented by using a C# Generic List(T) class.
noteNote:
If you are not writing managed code, you must write native C++ code that mimics the use of these wrapper classes.
First, the following class-level instance variables are declared in the standard ThisAddin class in Visual Studio 2008 with Visual Studio Tools for Office.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;

namespace RibbonXOutlook14AddinCS
{
    public partial class ThisAddIn
    {
        #region Instance Variables
        Outlook.Application m_Application;             
        Outlook.Explorers m_Explorers;
        Outlook.Inspectors m_Inspectors;
        public stdole.IPictureDisp m_pictdisp = null;
        // List of tracked explorer windows.         
        internal static List<OutlookExplorer> m_Windows;
        // List of traced inspector windows.
        internal static List<OutlookInspector> m_InspectorWindows;
        // Ribbon UI reference.
        internal static Office.IRibbonUI m_Ribbon;
        #endregion
        ...
    }
}

Once the instance variables have been declared, they are used in the Startup method of the ThisAddin class that is provided to all Visual Studio 2008 with Visual Studio Tools for Office add-ins. In the Startup method, which typically occurs when Outlook starts, the code first hooks up an event handler to respond to the NewExplorer event on the Outlook Explorers collection object. After the NewExplorer event has been handled, the active explorer window is added by using the following code.
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    // Initialize variables.
    m_Application = this.Application;
    m_Explorers = m_Application.Explorers;
    m_Inspectors = m_Application.Inspectors;
    m_Windows = new List<OutlookExplorer>();
    m_InspectorWindows = new List<OutlookInspector>();

    // Wire up event handlers to handle multiple Explorer windows.
    m_Explorers.NewExplorer += 
        new Outlook.ExplorersEvents_NewExplorerEventHandler(
            m_Explorers_NewExplorer);
    // Wire up event handler to handle multiple Inspector windows.
    m_Inspectors.NewInspector += 
        new Outlook.InspectorsEvents_NewInspectorEventHandler(
            m_Inspectors_NewInspector);
    // Add the ActiveExplorer to m_Windows.
    Outlook.Explorer expl = m_Application.ActiveExplorer()
        as Outlook.Explorer;
    OutlookExplorer window = new OutlookExplorer(expl);
    m_Windows.Add(window);
    // Hook up event handlers for window.
    window.Close += new EventHandler(WrappedWindow_Close);
    window.InvalidateControl += new EventHandler<
        OutlookExplorer.InvalidateEventArgs>(
        WrappedWindow_InvalidateControl);
    // Get IPictureDisp for CurrentUser on startup.
    try
    {
        Outlook.AddressEntry addrEntry = 
            Globals.ThisAddIn.Application.Session.CurrentUser.AddressEntry;
        if (addrEntry.Type == "EX")
        {
            Outlook.ExchangeUser exchUser = 
                addrEntry.GetExchangeUser() as Outlook.ExchangeUser;
            m_pictdisp = exchUser.GetPicture() as stdole.IPictureDisp;
        }
    }
    catch (Exception ex)
    {
        // Write exception to debug window.
        Debug.WriteLine(ex.Message);
    }
}

Just after Outlook starts, Office calls GetCustomUIGetCustomUI is the method of the IRibbonExtensibility interface that loads custom XML markup. In Outlook 2007, Office called GetCustomUI when the first instance of a given inspector type, such as a contact or appointment, was displayed. In Outlook 2010, Office calls GetCustomUI before theThisAddin.Startup method to accommodate the loading of ribbon customizations for the Outlook explorer ribbon. Because Office calls GetCustomUI only once for the first Outlook explorer during startup and multiple times for the first instance of multiple inspector types, consider using a Switch statement to control loading of XML markup for different customized Ribbons. For each ribbon in Outlook, GetCustomUI is called and Office passes the ribbon ID string that identifies the ribbon that is being loaded in Outlook. For a complete listing of ribbon IDs, see the section Ribbon Identifiers.
In the sample code, there are three XML markup files:
  • ContactCard.xml
  • Explorer.xml
  • ReadMail.xml
ContactCard.xml contains XML markup for context menus on the Contact Card. Explorer.xml contains XML markup for the explorer ribbon, context menus, and Backstage view. Readmail.xml contains XML markup for a read mail inspector.
To get a better idea of how this technique works, examine the following code from the GetCustomUI method in the OutlookRibbonX class.
        
public string GetCustomUI(string ribbonID)
{
    string customUI = string.Empty;
    Debug.WriteLine(ribbonID);
    // Return the appropriate XML markup for ribbonID.
    switch (ribbonID)
    {
        case "Microsoft.Outlook.Explorer":
            customUI = GetResourceText( 
                "RibbonXOutlook14AddinCS.Explorer.xml");
            return customUI;
        case "Microsoft.Outlook.Mail.Read":
            customUI= GetResourceText(
                "RibbonXOutlook14AddinCS.ReadMail.xml");
            return customUI;
        case "Microsoft.Mso.IMLayerUI":
            customUI = GetResourceText(
                "RibbonXOutlook14AddinCS.ContactCard.xml");
            return customUI;
        default:
            return string.Empty;
    }
}

Take a look at the sample solution for a complete listing of ContactCard.xml, Explorer.xml, and ReadMail.xml. Once custom XML markup has been loaded for each add-in, it is time to write code in Fluent UI extensibility callbacks to hide and show the tab named MyTab, depending on whether the selected item in the explorer is a received mail item. To complete the scenario, you must hook up another set of events in the constructor of the OutlookExplorer class.
        
public OutlookExplorer(Outlook.Explorer explorer)
{
    m_Window = explorer;
        
    // Hook up Close event.
    ((Outlook.ExplorerEvents_Event)explorer).Close +=
        new Outlook.ExplorerEvents_CloseEventHandler(
        OutlookExplorerWindow_Close);

    // Hook up SelectionChange event.
    m_Window.SelectionChange += 
        new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(
        m_Window_SelectionChange);
}

The SelectionChange event handler is very straightforward. The SelectionChange event occurs whenever the user changes the selection in an explorer window. WhenSelectionChange occurs, the RaiseInvalidateControl method is called and the control ID "MyTab" is passed to the method. RaiseInvalidateControl calls an event delegate named WrappedWindow_InvalidateControl in the ThisAddin class.
        
private void m_Window_SelectionChange()
{
    RaiseInvalidateControl("MyTab");
} 
void WrappedWindow_InvalidateControl(object sender,
    OutlookExplorer.InvalidateEventArgs e)
{
    if (m_Ribbon != null)
    {
        m_Ribbon.InvalidateControl(e.ControlID);
    }
}

The m_Ribbon variable represents an IRibbonUI object. When the InvalidateControl method of the IRibbonUI object is called, ribbon callbacks occur for the "MyTab" control. You could also call the Invalidate method of IRibbonUI, but that method causes callbacks for all of the controls that your add-in adds to the ribbon. In general, make your invalidation more granular than global, especially when your callbacks load image resources with a getImage callback. For the "MyTab" control, a getVisible callback has been defined in the RibbonXAddin class that controls the visibility of the tab. If the getVisible callback returns True, the tab is visible; otherwise, "MyTab" is hidden. The following code is the MyTab_GetVisible callback in its entirety.
        
// Only show MyTab when explorer selection is 
// a received mail or when inspector is a read note.
public bool MyTab_GetVisible(Office.IRibbonControl control)
{
    if (control.Context is Outlook.Explorer)
    {
        Outlook.Explorer explorer = 
            control.Context as Outlook.Explorer;
        Outlook.Selection selection = explorer.Selection;
        if (selection.Count == 1)
        {
            if (selection[1] is Outlook.MailItem)
            {
                Outlook.MailItem oMail = 
                    selection[1] as Outlook.MailItem;
                if (oMail.Sent == true)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else if (control.Context is Outlook.Inspector)
    {
        Outlook.Inspector oInsp = 
            control.Context as Outlook.Inspector;
        if (oInsp.CurrentItem is Outlook.MailItem)
        {
            Outlook.MailItem oMail = 
                oInsp.CurrentItem as Outlook.MailItem;
            if (oMail.Sent == true)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return true;
    }
}

This walkthrough detailed the most important strategies for extending the ribbon in Outlook 2010. In summary, your code should support the following:
  • The use of multiple explorer or inspector windows in Outlook 2010. Wrap the windows in a separate class instance that can raise events appropriate to that specific window.
  • The appropriate use of the InvalidateControl or Invalidate methods of the IRibbonUI interface to cause callbacks to occur.
  • The evaluation of different item types (based on the message class, built-in properties, or custom properties of a specific item type) in both event handlers and ribbon callbacks.

Ribbon Identifiers

The following table lists the ribbon IDs that are passed to the GetCustomUI method of the IRibbonExtensibility interface. Use the ribbon ID to determine the XML to return in the GetCustomUI method.

Table 1. Ribbon IDs and Message Class

Ribbon ID
Message class
Microsoft.OMS.MMS.Compose
IPM.Note.Mobile.MMS.*
Microsoft.OMS.MMS.Read
IPM.Note.Mobile.MMS.*
Microsoft.OMS.SMS.Compose
IPM.Note.Mobile.SMS.*
Microsoft.OMS.SMS.Read
IPM.Note.Mobile.SMS.*
Microsoft.Outlook.Appointment
IPM.Appointment.*
Microsoft.Outlook.Contact
IPM.Contact.*
Microsoft.Outlook.DistributionList
IPM.DistList.*
Microsoft.Outlook.Journal
IPM.Activity.*
Microsoft.Outlook.Mail.Compose
IPM.Note.*
Microsoft.Outlook.Mail.Read
IPM.Note.*
Microsoft.Outlook.MeetingRequest.Read
IPM.Schedule.Meeting.Request or IPM.Schedule.Meeting.Canceled
Microsoft.Outlook.MeetingRequest.Send
IPM.Schedule.Meeting.Request
Microsoft.Outlook.Post.Compose
IPM.Post.*
Microsoft.Outlook.Post.Read
IPM.Post.*
Microsoft.Outlook.Report
IPM.Report.*
Microsoft.Outlook.Resend
IPM.Resend.*
Microsoft.Outlook.Response.Compose
IPM.Schedule.Meeting.Resp.*
Microsoft.Outlook.Response.CounterPropose
IPM.Schedule.Meeting.Resp.*
Microsoft.Outlook.Response.Read
IPM.Schedule.Meeting.Resp.*
Microsoft.Outlook.RSS
IPM.Post.Rss.*
Microsoft.Outlook.Sharing.Compose
IPM.Sharing.*
Microsoft.Outlook.Sharing.Read
IPM.Sharing.*
Microsoft.Outlook.Task
IPM.Task.* and IPM.TaskRequest.*
Microsoft.Outlook.Explorer
Not applicable. Use this ribbon ID to return XML markup for explorer ribbons, context menus, and Backstage view.

Explorer

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

When Outlook 2010 starts, it calls the GetCustomUI method of the IRibbonExtensibility interface and specifies the ribbon ID in the RibbonID parameter for the add-in. The add-in should implement the GetCustomUI method such that if RibbonID is Microsoft.Outlook.Explorer, GetCustomUI returns the XML markup for explorer and context menu customizations.

XML Markup Example

  
<ribbon>
    <tabs>
        <tab id="MyTab"
            getVisible="MyTab_GetVisible"
            label="MyTab">
            <group label="MyGroup" id="MyGroup">
                <button id="MyButton"
                    size="large"
                    label="MyButton"
                    imageMso="HappyFace"
                    onAction="OnMyButtonClick"/>
            </group>
        </tab>
    </tabs>
</ribbon>

User Interface Example

Figure 1. Extending the explorer ribbon
Extending the explorer ribbon

Inspector

Ribbon ID

Outlook supports different ribbons in inspectors that display different item types. Depending on the message class of the item to be displayed in an inspector, the add-in should expect Outlook to pass the corresponding ribbon ID as the RibbonID parameter to the GetCustomUI method.

Table 2. Ribbon IDs and Message Class

Ribbon ID
Message Class
Microsoft.OMS.MMS.Compose
IPM.Note.Mobile.MMS.*
Microsoft.OMS.MMS.Read
IPM.Note.Mobile.MMS.*
Microsoft.OMS.SMS.Compose
IPM.Note.Mobile.SMS.*
Microsoft.OMS.SMS.Read
IPM.Note.Mobile.SMS.*
Microsoft.Outlook.Appointment
IPM.Appointment.*
Microsoft.Outlook.Contact
IPM.Contact.*
Microsoft.Outlook.DistributionList
IPM.DistList.*
Microsoft.Outlook.Journal
IPM.Activity.*
Microsoft.Outlook.Mail.Compose
IPM.Note.*
Microsoft.Outlook.Mail.Read
IPM.Note.*
Microsoft.Outlook.MeetingRequest.Read
IPM.Schedule.Meeting.Request or IPM.Schedule.Meeting.Canceled
Microsoft.Outlook.MeetingRequest.Send
IPM.Schedule.Meeting.Request
Microsoft.Outlook.Post.Compose
IPM.Post.*
Microsoft.Outlook.Post.Read
IPM.Post.*
Microsoft.Outlook.Report
IPM.Report.*
Microsoft.Outlook.Resend
IPM.Resend.*
Microsoft.Outlook.Response.Compose
IPM.Schedule.Meeting.Resp.*
Microsoft.Outlook.Response.CounterPropose
IPM.Schedule.Meeting.Resp.*
Microsoft.Outlook.Response.Read
IPM.Schedule.Meeting.Resp.*
Microsoft.Outlook.RSS
IPM.Post.Rss.*
Microsoft.Outlook.Sharing.Compose
IPM.Sharing.*
Microsoft.Outlook.Sharing.Read
IPM.Sharing.*
Microsoft.Outlook.Task
IPM.Task.* and IPM.TaskRequest.*

IRibbonControl.Context

Inspector object

Remarks

When Outlook 2010 displays the first inspector for a built-in message class, Outlook calls the GetCustomUI method of the IRibbonExtensibility interface and specifies the ribbon ID in the RibbonID parameter for the add-in. The add-in should implement the GetCustomUI method such that GetCustomUI returns the appropriate XML markup based on RibbonID.
Use the CurrentItem property of the Inspector object to return the item-level object such as MailItemAppointmentItemContactItem, or TaskItem.

XML Markup Example

  
<ribbon>
    <tabs>
        <tab id="MyTab"
            getVisible="MyTab_GetVisible"
            label="MyTab">
            <group label="MyGroup" id="MyGroup" >
                <button id="MyButton"
                    size="large"
                    label="MyButton"
                    imageMso="HappyFace"
                    onAction="OnMyButtonClick"/>
            </group>
        </tab>
    </tabs>
</ribbon>

User Interface Example

Figure 2. Extending the inspector ribbon
Extending the inspector ribbon

Folder Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Folder object

Remarks

When Outlook 2010 displays the following context menu, a folder is selected in the Folder List in the Navigation Pane.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuFolder">
        <button id="MyContextMenuFolder"
            label="ContextMenuFolder"
            onAction="OnMyButtonClick" />
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 3. Extending the context menu for a folder in the Folder List
Extending the context menu for a folder

Root Search Folder Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Folder object

Remarks

When Outlook 2010 displays the following context menu, the root search folder, Search Folders, is selected in the Folder List in the Navigation Pane.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuSearchRoot">
        <button id="MyContextMenuSearchRoot"
            label="ContextMenuSearchRoot"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 4. Extending the context menu for the root search folder
Extending the context menu for root search folder

Store Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Store object

Remarks

When Outlook 2010 displays the following context menu, a store folder is selected in the Folder List in the Navigation Pane.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuStore">
        <button id="MyContextMenuStore"
            label="ContextMenuStore"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 5. Extending the context menu for a store folder
Extending the context menu for a store folder

Context Menu for a Mail Item

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Selection object

Remarks

When Outlook 2010 displays the following context menu, a mail item is selected in the current view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuMailItem">
        <button id="MyContextMenuMailItem"
            label="ContextMenuMailItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 6. Extending the context menu for a mail item
Extending the context menu for a mail item

Context Menu for Multiple Selected Items

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Selection object

Remarks

When Outlook 2010 displays the following context menu, multiple items are selected in the current view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuMultipleItems">
        <button id="MyContextMenuMultipleItems"
            label="ContextMenuMultipleItems"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 7. Extending the context menu for multiple selected items
Extending context menu for multiple selected items

Context Menu for an Appointment or Meeting Request

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Selection object

Remarks

When Outlook 2010 displays the following context menu, an appointment or a meeting request is selected in the current calendar view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuCalendarItem">
        <button id="MyContextMenuCalendarItem"
            label="ContextMenuCalendarItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 8. Extending the context menu for a meeting request in the meeting organizer's calendar
Extending the context menu for a meeting request

Context Menu for a Task Item

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Selection object

Remarks

When Outlook 2010 displays the following context menu, a task item is selected in the current task view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuTaskItem">
        <button id="MyContextMenuTaskItem"
            label="ContextMenuTaskItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 9. Extending the context menu for a task item
Extending the content menu for a task item

Context Menu for a Contact Item

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Selection object

Remarks

When Outlook 2010 displays the following context menu, a contact item is selected in the current view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuContactItem">
        <button id="MyContextMenuContactItem"
            label="ContextMenuContactItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 10. Extending the context menu for a contact item
Extending the context menu for a contact item

Context Menu for a Journal Item

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Selection object

Remarks

When Outlook 2010 displays the following context menu, a journal item is selected in the current view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuJournalItem">
        <button id="MyContextMenuJournalItem" 
            label="ContextMenuJournalItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 11. Extending the context menu for a journal item
Extending the context menu for a journal item

Context Menu for a Note Item

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Selection object

Remarks

When Outlook 2010 displays the following context menu, a note item is selected in the current view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuNoteItem">
        <button id="MyContextMenuNoteItem"
            label="ContextMenuNoteItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 12. Extending the content menu for a note item
Extending the context menu for a note item

Shortcut Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Remarks

When Outlook 2010 displays the following context menu, a shortcut is selected in the Shortcuts module.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuShortcut">
        <button id="MyContextMenuShortcut"
            label="ContextMenuShortcut"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 13. Extending the context menu for a shortcut in the Shortcuts module
Extending the context menu for a shortcut

Attachment Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Remarks

When Outlook 2010 displays the following context menu, one or more attachments are selected in the Reading Pane in the explorer, or in an inspector.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuAttachments">
        <button id="MyContextMenuAttachments"
            label="ContextMenuAttachments"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 14. Extending the context menu for an attachment or attachments in the Reading Pane
Extending the context menu for attachments

Table View Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

View object

Remarks

Outlook 2010 displays the following context menu when a user displays the context menu in a table view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuTableView">
        <button id="MyContextMenuTableView"
            label="ContextMenuTableView"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 15. Extending the context menu in a table view
Extending the context menu in a table view

Calendar View Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

View object

Remarks

Outlook 2010 displays the following context menu when a user displays the context menu in a calendar view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuCalendarView">
        <button id="MyContextMenuCalendarView" 
            label="ContextMenuCalendarView" 
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 16. Extending the context menu in a calendar view
Extending the context menu in a calendar view

Card View Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

View object

Remarks

Outlook 2010 displays the following context menu when a user displays the context menu in a card view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuCardView">
        <button id="MyContextMenuCardView" 
            label="ContextMenuCardView" 
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 17. Extending the context menu in a card view
Extending the context menu in a card view

Timeline View Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

View object

Remarks

Outlook 2010 displays the following context menu when a user displays the context menu in a timeline view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuTimelineView">
        <button id="MyContextMenuTimelineView" 
            label="ContextMenuTimelineView" 
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 18. Extending the context menu in a timeline view
Extending the context menu in a timeline view

Menu for the Arrange By Command

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following menu when a user points to Arrange By in the context menu for a field in a table view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuTableArrangeBy">
        <button id="MyContextMenuTableArrangeBy" 
            label="ContextMenuTableArrangeBy" 
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 19. Extending the Arrange By menu in a table view
Extending the Arrange By menu in a table view

Context Menu for Time Bar

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following context menu when a user right-clicks the time bar in a calendar view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuCalendarViewTimeBar">
        <button id="MyContextMenuCalendarViewTimeBar" 
            label="ContextMenuCalendarViewTimeBar" 
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 20. Extending the context menu for the time bar in a calendar view
Extending the context menu for the time bar

Context Menu for Free/Busy Bar

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following context menu when a user right-clicks the free/busy bar in a calendar view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuCalendarViewFreeBusyBar">
        <button id="MyContextMenuCalendarViewFreeBusyBar" 
            label="ContextMenuCalendarViewFreeBusyBar" 
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 21. Extending the context menu for the free/busy bar in a calendar view
Extending the context menu for the free/busy bar

Context Menu for a Table View Column

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following context menu when a user right-clicks a column header in a table view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuTableViewColumn">
        <button id="MyContextMenuTableViewColumn" 
            label="ContextMenuTableViewColumn" 
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 22. Extending the context menu for a column in a table view
Extending the context menu for a table view column

Categories Context Menu

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following context menu when a user right-clicks a category or, if no category has been specified, the user right-clicks under the Category column in a table view.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuCategories">
        <button id="MyContextMenuCategories"
            label="ContextMenuCategories"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 23. Extending the context menu for a category
Extending the context menu for a category

Context Menu for Quick Flags

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following context menu when a user displays the context menu for a quick flag.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuQuickFlags">
        <button id="MyContextMenuQuickFlags"
            label="ContextMenuQuickFlags"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 24. Extending the context menu for quick flags
Extending the context menu for quick flags

Context Menu for Flagged Mail Item

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following context menu when a user displays the context menu for a flagged mail item in the To-Do Bar.

XML Markup Example

<contextMenus>    
    <contextMenu idMso="ContextMenuFlaggedMailItem">
        <button id="MyContextMenuFlaggedMailItem"
            label="ContextMenuFlaggedMailItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>
</contextMenus>

User Interface Example

Figure 25. Extending the context menu for a flagged mail item
Extending the context menu for a flagged mail item

Context Menu for Flagged Contact Item

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following context menu when a user displays the context menu for a flagged mail item in the To-Do Bar.

XML Markup Example

<contextMenus>    
    <contextMenu idMso="ContextMenuFlaggedContactItem">
        <button id="MyContextMenuFlaggedContactItem"
            label="ContextMenuFlaggedContactItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>
</contextMenus>

User Interface Example

Figure 26. Extending the context menu for a flagged contact item
Extending context menu for a flagged contact item

New Items Menu for Mail Module

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following menu when a user selects New Items in the Home tab of the explorer ribbon for the Mail module. Although the New Items menu is not a context menu, the markup for a custom menu item should be placed inside the <contextMenus></contextMenus> tags. That way, you can add a command for an item that is based on a custom message class to the built-in New Items menu.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="MenuMailNewItem">
        <button id="MyMenuMailNewItem"
            label="MenuNewMailItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 27. Extending the New Items menu for the Mail module
Extending the New Items menu for the Mail module

New Items Menu for Calendar Module

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following menu when a user clicks New Items in the Home tab of the explorer ribbon for the Calendar module. Although the New Items menu is not a context menu, the markup for a custom menu item should be placed inside the <contextMenus></contextMenus> tags. That way, you can add a command for an item that is based on a custom message class to the built-in New Items menu.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="MenuCalendarNewItem">
        <button id="MyMenuCalendarNewItem"
            label="MenuCalendarNewItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 28. Extending the New Items menu for the Calendar module
Extending New Items menu for Calendar module

New Items Menu for Contacts Module

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following menu when a user clicks New Items in the Home tab of the explorer ribbon for the Contacts module. Although the New Items menu is not a context menu, the markup for a custom menu item should be placed inside the <contextMenus></contextMenus> tags. That way, you can add a command for an item that is based on a custom message class to the built-in New Items menu.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="MenuContactsNewItem">
        <button id="MyMenuContactsNewItem"
            label="MenuContactsNewItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 29. Extending the New Items menu for the Contacts module
Extending New Items menu for Contacts module

New Items Menu for Tasks Module

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following menu when a user clicks New Items in the Home tab of the explorer ribbon for the Tasks module. Although the New Items menu is not a context menu, the markup for a custom menu item should be placed inside the <contextMenus></contextMenus> tags. That way, you can add a command for an item that is based on a custom message class to the built-in New Items menu.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="MenuTasksNewItem">
        <button id="MyMenuTasksNewItem"
            label="MenuTasksNewItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 30. Extending the New Items menu for the Tasks module
Extending the New Items menu for the Tasks module

New Items Menu for Journal Module

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following menu when a user clicks New Items in the Home tab of the explorer ribbon for the Journal module. Although the New Items menu is not a context menu, the markup for a custom menu item should be placed inside the <contextMenus></contextMenus> tags. That way, you can add a command for an item that is based on a custom message class to the built-in New Items menu.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="MenuJournalNewItem">
        <button id="MyMenuJournalNewItem"
            label="MenuJournalNewItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 31. Extending the New Items menu for the Journal module
Extending New Items menu for Journal module

New Items Menu for Notes Module

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object

Remarks

Outlook 2010 displays the following menu when a user clicks New Items in the Home tab of the explorer ribbon for the Notes module. Although the New Items menu is not a context menu, the markup for a custom menu item should be placed inside the <contextMenus></contextMenus> tags. That way, you can add a command for an item that is based on a custom message class to the built-in New Items menu.

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="MenuNotesNewItem">
        <button id="MyMenuNotesNewItem"
            label="MenuNotesNewItem"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 32. Extending the New Items menu for the Notes module
Extending the New Items menu for the Notes module

Persona Context Menu for a Sender or Recipient

Ribbon ID

Microsoft.Mso.IMLayerUI

IRibbonControl.Context

Office.IMsoContactCard object

Remarks

Outlook 2010 displays the persona context menu when a user right-clicks a sender or a recipient of an Outlook item. To determine the identity of the sender or recipient, use the Address property of the IMsoContactCard object in the Office object model to obtain an AddressEntry object in the Outlook object model, which represents the recipient as shown in the following code example.
if (control.Context is Microsoft.Office.Core.IMsoContactCard)
{
    msg = "Context=IMsoContactCard" + "\n";
    Office.IMsoContactCard card = control.Context as Office.IMsoContactCard;
    Outlook.AddressEntry addr =
        Globals.ThisAddIn.Application.Session.GetAddressEntryFromID(
        card.Address);
    if (addr != null)
    {
        msg = msg + addr.Name;
    }
    MessageBox.Show(msg);
}

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuContactCardRecipient">
        <button id="MyContextMenuContactCardRecipient"
            label="ContextMenuContactCardRecipient"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 33. Extending the persona context menu for a recipient
Extending the persona context menu

Menu for Alternative Interactions

Ribbon ID

Microsoft.Mso.IMLayerUI

IRibbonControl.Context

Office.IMsoContactCard object

Remarks

To interact with a contact by using a way other than e-mail, instant message, or phone, a user can specify an alternative form on the shortcut menu that is on a Contact Card. To display a Contact Card, a user can rest the pointer on, click, or right-click a sender or recipient of an Outlook item.
To determine the identity of the sender or recipient, use the Address property of the IMsoContactCard object in the Office object model to obtain an AddressEntry object in the Outlook object model, which represents the recipient as shown in the following code example.
if (control.Context is Microsoft.Office.Core.IMsoContactCard)
{
    msg = "Context=IMsoContactCard" + "\n";
    Office.IMsoContactCard card = control.Context as Office.IMsoContactCard;
    Outlook.AddressEntry addr =
        Globals.ThisAddIn.Application.Session.GetAddressEntryFromID
        (card.Address);
    if (addr != null)
    {
        msg = msg + addr.Name;
    }
    MessageBox.Show(msg);
}

XML Markup Example

  
<contextMenus>    
    <contextMenu idMso="ContextMenuContactCardOverflowDropdown">
        <button id="MyContextMenuContactCardOverflow"
            label="ContextMenuContactCardOverflow"
            onAction="OnMyButtonClick"/>
    </contextMenu>  
</contextMenus>

User Interface Example

Figure 34. Extending the other-interaction menu for a contact
Extending the other-interaction menu for a contact

Contextual Tabs

Ribbon ID

Microsoft.Outlook.Explorer or appropriate Inspector RibbonID

IRibbonControl.Context

Explorer object or Inspector object

Remarks

Contextual tabs appear when a user selects an object in the Outlook user interface with the intent to edit or modify that object. Customizing a contextual tab is similar to customizing a built-in ribbon tab, but the markup for customization uses <contextualTabs></contextualTabs> tags instead of <tabs></tabs>. Contextual tabs are used extensively in Outlook 2010. The following example shows how to customize the contextual tab for attachments named Attachment Tools.The Attachment Context Menudescribed previously adds a context menu item that can act on the selected attachment. To create an equivalent command in the Attachment Tools contextual tab, you need to supply XML markup as shown in the following XML markup example and then determine the selected attachment by using the AttachmentSelection object returned byIRibbonControl.Context as shown in the following C# code fragment:
    else if (control.Context is Outlook.Explorer)
    {
        msg = "Context=Explorer" + "\n";
        Outlook.Explorer explorer = 
            control.Context as Outlook.Explorer;
            if (explorer.AttachmentSelection.Count >= 1)
            {
                Outlook.AttachmentSelection attachSel =
                    explorer.AttachmentSelection;
                foreach (Outlook.Attachment attach in attachSel)
                {
                    msg = msg + attach.DisplayName + "\n";
                }
            }
            else
            {
                Outlook.Selection selection =
                    explorer.Selection;
                if (selection.Count == 1)
                {
                    OutlookItem olItem =
                        new OutlookItem(selection[1]);
                    msg = msg + olItem.Subject
                        + "\n" + olItem.LastModificationTime;
                }
                else
                {
                    msg = msg + "Multiple Selection Count="
                        + selection.Count;
                }
            }
        }
    }    

XML Markup Example

<contextualTabs>
    <tabSet idMso="TabSetAttachments">
        <tab idMso="TabAttachments">
            <group label="MyGroup" id="MyAttachmentGroup">
                <button id="MyButtonAttachments"
                    size="large"
                    label="MyButtonAttachments"
                    imageMso="HappyFace"
                    onAction="OnMyButtonClick" />
            </group>
        </tab>
    </tabSet>
</contextualTabs>

User Interface Example

Figure 35. Extending the Attachments tab with an Attachment Tools contextual tab for an Outlook explorer
Extending the Attachments tab

Backstage View

Ribbon ID

Microsoft.Outlook.Explorer

IRibbonControl.Context

Explorer object or Inspector object

Remarks

Backstage view helps users to find commonly used features and to discover new ways to work with their documents. To access Backstage view, click the File tab that appears to the left of the Home tab. In Outlook 2010, you can use Backstage view to expose application-level settings for an add-in. Consider customizing Backstage view to replace the property page extensions that were accessible when you clicked Tools and then Options in earlier versions of Outlook. Property page extensions continue to work in Outlook 2010, but users might not find them easily. To access add-in property page extensions, open Backstage view, click the Options command to display the Outlook Options dialog box, click the Add-ins tab, and then click the Add-in Options button.
Outlook 2010 can display Backstage view in either an explorer or inspector window. Use the IRibbonControl.Context property to determine whether Backstage view is hosted in an explorer or inspector window.
A tab in Backstage view is a functional unit. Backstage view contains default tabs. For example, Backstage view for the Outlook explorer contains the InfoOpenPrint, andHelp tabs. If you want to create a custom tab and show it in only an Outlook explorer or inspector window, use the GetVisible callback. The following C# code example causes the MyPlace tab to be visible only in the explorer window.
public bool MyPlace_GetVisible(IRibbonControl control)
{
    if (control.Context is Microsoft.Office.Interop.Outlook.Explorer)
        return true;
    else
        return false;
}

XML Markup Example

<backStage>
    <tab id="MyBackStageTab"
        label="MyTab"
        getVisible="MyBackStageTab_GetVisible">
        <firstColumn>
            <group id="regularGroup"
                label="My Regular Group"
                helperText="My Regular Group Helper Text">
                <primaryItem>
                    <button id="MyHeroButton"
                        label="My Hero Button"
                        imageMso="MagicEightBall"
                        isDefinitive="false"
                        onAction="OnMyButtonClick"
                        screentip="Click to spin the magic eight ball."/>
                </primaryItem>
                <bottomItems>
                    <hyperlink
                        id="hyperlink"
                        label="Office Developer Center"
                        target="http://msdn.microsoft.com/en-us/office/default.aspx"/>
                    <imageControl id="userImage"
                        getImage="GetCurrentUserImage"/>
                    <layoutContainer id="vertical"
                        align="left"
                        layoutChildren="vertical">
                        <labelControl id="labelControl2" 
                            label="Vertical layout"/>
                        <radioGroup id="myradiogroup1" label="Options">
                            <radioButton id="rb1" label="Option 1"/>
                            <radioButton id="rb2" label="Option 2"/>
                            <radioButton id="rb3" label="Option 3"/>
                        </radioGroup>
                    </layoutContainer>
                    <groupBox id="mygroupbox1" label="Check Boxes">
                        <checkBox id="check1" label="Check Box 1"/>
                        <checkBox id="check2" label="Check Box 2"/>
                        <checkBox id="check3" label="Check Box 3"/>
                    </groupBox>
                    <layoutContainer id="vertical2"
                        align="left"
                        layoutChildren="vertical">
                        <comboBox id="comboBox" label="Color ComboBox">
                            <item id="cbi1" label="Blue"/>
                            <item id="cbi2" label="Magenta"/>
                            <item id="cbi3" label="Cyan"/>
                        </comboBox>
                    </layoutContainer>
                </bottomItems>
            </group>
            <taskGroup id="taskGroup"
                label="My Task Group"
                helperText="My Task Group Helper Text">
                <category id="MyCategory" label="My Category">
                <task id="MyTask"
                    tag="MyTask"
                    isDefinitive="true"
                    label="My Task"
                    imageMso="NewTask"/>
                </category>
            </taskGroup>
        </firstColumn>
        <secondColumn>
            <group id="myemptygroup">
            </group>
        </secondColumn>
    </tab>
</backstage>

User Interface Example

Figure 36. Extending Backstage view for an Outlook explorer
Extending Backstage view for an Outlook explorer

Conclusion

In the 2007 Microsoft Office system, the Fluent UI includes the ribbon, menus, enhanced screen tips, a Mini toolbar, and keyboard shortcuts that appear in various Office applications. Office 2010 adds Backstage view to the Fluent UI. Fluent UI extensibility supports the ability to customize Fluent UI components programmatically. For example, Outlook 2010 provides many ways to extend the ribbon in an explorer or inspector, the menus, the context menus, and Backstage view. The principles behind programmatic extensions to the Fluent UI are all very similar; all involve using IRibbonExtensibility.GetCustomUI to specify XML markup for the custom UI and writing callbacks in an add-in to respond to user actions on the custom UI. The consistent extensibility design makes it easier for Outlook 2010 add-in developers to further enhance their UI.