共用方式為


逐步解說:在執行階段更新功能區中的控制項

更新:2007 年 11 月

適用於

本主題中的資訊僅適用於指定的 Visual Studio Tools for Office 專案和 Microsoft Office 版本。

專案類型

  • 文件層級專案

  • 應用程式層級專案

Microsoft Office 版本

  • Excel 2007

  • Word 2007

  • Outlook 2007

  • PowerPoint 2007

如需詳細資訊,請參閱依應用程式和專案類型提供的功能

本逐步解說會示範如何在功能區載入 Office 應用程式之後,使用功能區物件模型更新功能區中的控制項。

範例會從 AdventureWorks 範例資料庫提取資料,並填入 (Populate) Microsoft Office Outlook 的下拉式方塊和功能表中。

這個逐步解說將說明下列工作:

  • 建立新的 Outlook 增益集專案。

  • 設計自訂功能區群組。

  • 將自訂群組加入至內建索引標籤。

  • 在執行階段更新功能區中的控制項。

注意事項:

在下列指示的某些 Visual Studio 使用者介面項目中,您的電腦可能會顯示不同的名稱或位置。您所擁有的 Visual Studio 版和使用的設定,會決定這些項目。如需詳細資訊,請參閱 Visual Studio 設定

必要條件

您需要下列元件才能完成此逐步解說:

  • Visual Studio Tools for Office (Visual Studio 2008 Professional 和 Visual Studio Team System 的選擇性元件)。

  • Microsoft Office Outlook 2007。

  • SQL Server Express 之 AdventureWorks 範例資料庫的存取權限。如需如何安裝 AdventureWorks 資料庫的詳細資訊,請參閱逐步解說:安裝 AdventureWorks 資料庫

Visual Studio Tools for Office 預設會與列出的 Visual Studio 版本一併安裝。若要查看是否已安裝,請參閱安裝 Visual Studio Tools for Office

建立新的 Outlook 增益集專案

首先,請建立 Outlook 增益集專案。

若要建立新的 Outlook 增益集專案

  1. 在 Visual Studio 中,建立名稱為 MyOutlookAddIn 的 Outlook 2007 增益集專案。

  2. 選取 [新增專案] 對話方塊中的 [為方案建立目錄]。

  3. 將專案儲存到預設的專案目錄。

    如需詳細資訊,請參閱 HOW TO:建立 Visual Studio Tools for Office 專案

設定自訂功能區群組

功能區不會出現在 Outlook 的主要介面區域,所以此範例的功能區將會在使用者撰寫新郵件時出現。若要建立功能區的自訂群組,請先將功能區項目加入至專案,然後使用功能區設計工具來設計群組。此自訂群組將協助您從資料庫提取名稱和訂單記錄,以產生後續要給客戶的郵件。

若要設計自訂群組

  1. 在 [專案] 功能表上按一下 [加入新項目]。

  2. 選取 [加入新項目] 對話方塊中的 [功能區 (視覺化設計工具)]。

  3. 將新功能區的名稱變更為 CustomerRibbon,然後按一下 [加入]。

    CustomerRibbon.cs 或 CustomerRibbon.vb 檔案會在功能區設計工具中開啟,並顯示預設索引標籤和群組。

  4. 按一下 [功能區設計工具] 予以選取。

  5. 在 [檢視] 功能表中,按一下 [屬性視窗]。

  6. 在 [屬性] 視窗中,按一下 [RibbonType] 屬性旁邊的下拉式箭頭,然後按一下 [Microsoft.Outlook.Mail.Compose]。

    這樣一來,當使用者在 Outlook 中撰寫新郵件時,功能區就會跟著出現。

  7. 按一下功能區設計工具中的 [Group1] 加以選取。

  8. 將 [屬性] 視窗中的 [Label] 設定為 Customer Purchases。

  9. 從 [工具箱] 的 [Office 功能區控制項] 索引標籤,將 [ComboBox] 拖曳至 [Customer Purchases] 群組。

  10. 按一下 [ComboBox1] 予以選取。

  11. 將 [屬性] 視窗中的 [Label] 設定為 Customers。

  12. 從 [工具箱] 的 [Office 功能區控制項] 索引標籤,將 [Menu] 拖曳至 [Customer Purchases] 群組。

  13. 將 [屬性] 視窗中的 [Label] 設定為 Product Purchased。

  14. 將 [Dynamic] 設定為 true。

    這樣一來,您就可以在功能區載入至 Office 應用程式後的執行階段,將項目加入至功能表或從功能表移除項目。

將自訂群組加入至內建索引標籤

內建索引標籤是已在 Outlook 偵測器功能區上的索引標籤。在此程序中,您會將自訂群組加入至內建索引標籤,然後指定自訂群組在索引標籤上的位置。

若要將自訂群組加入至內建索引標籤

  1. 按一下 [TabAddins (內建)] 索引標籤加以選取。

  2. 在 [屬性] 視窗中展開 [ControlId] 屬性,然後將 [OfficeId] 設定為 TabNewMailMessage。

    這樣會將 [Customer Purchases] 群組加入至出現在新郵件之功能區的 [訊息] 索引標籤中。

  3. 按一下 [Customer Purchases] 群組加以選取。

  4. 展開 [屬性] 視窗中的 [Position] 屬性,然後按一下 [PositionType] 屬性旁邊的下拉式箭頭,再按一下 [BeforeOfficeId]。

  5. 將 [OfficeId] 屬性設定為 GroupClipBoard。

    這樣會將 [Customer Purchases] 群組置於 [訊息] 索引標籤中的 [剪貼簿] 群組之前。

在執行階段更新自訂群組中的控制項

請使用功能區物件模型執行下列工作:

  • 將客戶名稱加入至 [Customers] 下拉式方塊。

  • 將功能表和核取方塊控制項加入至代表銷售訂單和售出產品的 [Products Purchased] 功能表。

  • 使用來自 [Customers] 下拉式方塊和 [Products Purchased] 功能表的資料,填入新郵件的 Microsoft.Office.Interop.Outlook.MailItem.ToMicrosoft.Office.Interop.Outlook.MailItem.SubjectMicrosoft.Office.Interop.Outlook.MailItem.Body 欄位。

若要使用功能區物件模型更新自訂群組中的控制項

  1. 在 [專案] 功能表上,按一下 [加入參考]。

  2. 按一下 [加入參考] 對話方塊中的 [.NET] 索引標籤,然後選取 [System.Data.Linq] 組件,再按一下 [確定]。

    此組件包含支援使用 Language-Integrated Queries (LINQ) 的類別。您將透過 LINQ 並使用來自 AdventureWorks 資料庫的資料來填入自訂群組中的控制項。如需 LINQ 的詳細資訊,請參閱 Language-Integrated Query (LINQ)

  3. 按一下 [方案總管] 中的 CustomerRibbon.cs 或 CustomerRibbon.vb 加以選取。

  4. 在 [檢視] 功能表上,按一下 [程式碼]。

    功能區程式碼檔案隨即在程式碼編輯器中開啟。

  5. 在功能區程式碼檔的頂端加入下列陳述式。這些陳述式可讓您方便存取 LINQ 命名空間和 Outlook 主要 Interop 組件 (PIA) 的命名空間。

    Imports Microsoft.Office.Tools.Ribbon
    Imports System.Data.Linq
    Imports System.Linq
    Imports System.Data.Linq.Mapping
    Imports System.Linq.Expressions
    Imports Outlook = Microsoft.Office.Interop.Outlook
    
    using System.Data.Linq;
    using System.Linq;
    using System.Data.Linq.Mapping;
    using System.Linq.Expressions;
    using Outlook = Microsoft.Office.Interop.Outlook;
    using System.IO;
    
  6. 將下列類別加入至功能區程式碼檔案。您將使用這些類別儲存來自 AdventureWorks 資料庫中 Customer、Contact、Sales Order Header、Sales Order Detail 和 Product 資料表的資訊。

    ' Customer Table.
    <Table(Name:="Sales.Customer")> _
    Public Class Customer
        <Column(IsPrimaryKey:=True)> _
            Public CustomerID As Integer
    End Class
    
    ' Contact Table.
    <Table(Name:="Person.Contact")> _
    Public Class Contact
        <Column(IsPrimaryKey:=True)> _
           Public ContactID As Integer
        <Column()> _
        Public LastName As String
    
    End Class
    ' Sales Order Header Table.
    <Table(Name:="Sales.SalesOrderHeader")> _
    Public Class SalesOrderHeader
        <Column(IsPrimaryKey:=True)> _
           Public SalesOrderID As Integer
        <Column()> _
       Public SalesOrderNumber As String
        <Column()> _
        Public CustomerID As Integer
    End Class
    
    ' Sales Order Detail Table.
    <Table(Name:="Sales.SalesOrderDetail")> _
    Public Class SalesOrderDetail
        <Column(IsPrimaryKey:=True)> _
           Public SalesOrderDetailID As Integer
        <Column()> _
       Public SalesOrderID As Integer
        <Column()> _
        Public ProductID As Integer
    End Class
    
    ' Product Table.
    <Table(Name:="Production.Product")> _
    Public Class Product
        <Column(IsPrimaryKey:=True)> _
           Public ProductID As Integer
        <Column()> _
        Public Name As String
    End Class
    ' Data Context Class.
    Partial Public Class AdventureWorks
        Inherits DataContext
        Public Customer As Table(Of Customer)
        Public Contact As Table(Of Contact)
        Public SalesOrderHeader As Table(Of SalesOrderHeader)
        Public SalesOrderDetail As Table(Of SalesOrderDetail)
        Public Product As Table(Of Product)
        Public Sub New(ByVal connection As String)
            MyBase.New(connection)
        End Sub
    End Class
    
    // Customer Table.
    [Table(Name = "Sales.Customer")]
    public class Customer
    {
        [Column(IsPrimaryKey = true)]
        public int CustomerID;
    }
    
    // Contact Table.
    [Table(Name = "Person.Contact")]
    public class Contact
    {
        [Column(IsPrimaryKey = true)]
        public int ContactID;
        [Column]
        public string LastName;
    
    }
    // Sales Order Header Table.
    [Table(Name = "Sales.SalesOrderHeader")]
    public class SalesOrderHeader
    {
        [Column(IsPrimaryKey = true)]
        public int SalesOrderID;
    
        [Column]
        public string SalesOrderNumber;
    
        [Column]
        public int CustomerID;
    
    }
    // Sales Order Detail Table.
    [Table(Name = "Sales.SalesOrderDetail")]
    public class SalesOrderDetail
    {
        [Column(IsPrimaryKey = true)]
        public int SalesOrderDetailID;
    
        [Column]
        public int SalesOrderID;
    
        [Column]
        public int ProductID;
    
    }
    // Product Table.
    [Table(Name = "Production.Product")]
    public class Product
    {
        [Column(IsPrimaryKey = true)]
        public int ProductID;
    
        [Column]
        public string Name;
    
    }
    // Data Context Table.
    public partial class AdventureWorks : DataContext
    {
        public Table<Customer> Customer;
        public Table<Contact> Contact;
        public Table<SalesOrderHeader> SalesOrderHeader;
        public Table<SalesOrderDetail> SalesOrderDetail;
        public Table<Product> Product;
        public AdventureWorks(string connection) : base(connection) { }
    }
    
  7. 以下列程式碼取代 CustomerRibbon_Load 事件處理常式方法。此程式碼使用 LINQ 查詢執行下列工作:

    • 使用 AdventureWorks 資料庫中 20 位客戶的 ID 和名稱來填入 [Customers] 下拉式方塊。

    • 呼叫 PopulateSalesOrderInfo Helper 方法。此方法會以屬於目前選取之客戶的銷售訂單編號來更新 [ProductsPurchased] 功能表。

     Private Sub CustomerRibbon_Load(ByVal sender As System.Object, _
    ByVal e As Microsoft.Office.Tools.Ribbon.RibbonUIEventArgs) _
        Handles MyBase.Load
    
         Dim programFilesDir As String = Environment.GetFolderPath _
         (Environment.SpecialFolder.ProgramFiles)
         Dim db As New AdventureWorks(programFilesDir + _
             "\Microsoft SQL Server\" + "MSSQL.1\MSSQL\Data\AdventureWorks_Data.mdf")
    
         Dim customerQuery = From customers In db.Customer.Take(20), contact In db.Contact _
                             Where customers.CustomerID = contact.ContactID _
                 Select CustomerID = customers.CustomerID, LastName = _
                     contact.LastName
    
         ' Execute the query.
         For Each item In customerQuery
             Me.ComboBox1.Items.Add(New RibbonDropDownItem())
             Me.ComboBox1.Items.Last().Label = item.CustomerID.ToString() _
                 + "|" + item.LastName
         Next item
    
         Me.ComboBox1.Text = Me.ComboBox1.Items.First().Label
         PopulateSalesOrderInfo()
     End Sub
    
    
    private void CustomerRibbon_Load(object sender, RibbonUIEventArgs e)
    {
        string programFilesDir = Environment.GetFolderPath
            (Environment.SpecialFolder.ProgramFiles);
        AdventureWorks db = new AdventureWorks
            (programFilesDir + "\\Microsoft SQL Server\\" + 
        "MSSQL.1\\MSSQL\\Data\\AdventureWorks_Data.mdf");
        var customerQuery = from customers in db.Customer.Take(20)
                            join contacts in db.Contact on 
                                customers.CustomerID 
                            equals contacts.ContactID
                            select new { customers.CustomerID, 
                                contacts.LastName };
    
    
        // Execute the query.
        foreach (var item in customerQuery)
        {
            this.comboBox1.Items.Add(new RibbonDropDownItem());
            this.comboBox1.Items.Last().Label = 
                item.CustomerID.ToString() + "|" + item.LastName;
        }
        this.comboBox1.Text = this.comboBox1.Items.First().Label;
        PopulateSalesOrderInfo();
    }
    
  8. 將下列程式碼加入至 CustomerRibbon 類別。此程式碼使用 LINQ 查詢執行下列工作:

    • 將子功能表加入至與目前選取客戶相關之每筆銷售訂單的 [ProductsPurchased] 功能表中。

    • 將核取方塊加入至銷售訂單相關產品的每個子功能表中。

    • 將事件處理常式加入至每個核取方塊中。

     Private Sub PopulateSalesOrderInfo()
    
         Dim tempArray As [String]() = comboBox1.Text.Split(New [Char]() {"|"c})
         Menu1.Items.Clear()
         Dim programFilesDir As String = Environment.GetFolderPath _
             (Environment.SpecialFolder.ProgramFiles)
         Dim db As New AdventureWorks(programFilesDir + _
             "\Microsoft SQL Server\" + "MSSQL.1\MSSQL\Data\AdventureWorks_Data.mdf")
    
    
         Dim orderQuery = From orders In db.SalesOrderHeader _
                          Where orders.CustomerID.ToString() = tempArray(0) _
                          Select SalesOrderID = _
                              orders.SalesOrderID, SalesOrderNumber = _
                                  orders.SalesOrderNumber
    
         For Each orderItem In orderQuery
             Dim Menu2 As New RibbonMenu()
             Menu2.Dynamic = True
             Menu1.Items.Add(Menu2)
             CType(Menu1.Items.Last(), RibbonMenu).Label = _
                 orderItem.SalesOrderNumber.ToString()
             CType(Menu1.Items.Last(), RibbonMenu).Tag = _
                 orderItem.SalesOrderID
    
             Dim productQuery = From orderDetail In db.SalesOrderDetail, _
                                    product In db.Product _
                                Where orderDetail.ProductID = _
                                    product.ProductID _
                                And orderDetail.SalesOrderID = _
                                orderItem.SalesOrderID _
             Select productName = product.Name
    
             For Each productItem In productQuery
                 CType(Menu1.Items.Last(), RibbonMenu).Items.Add _
                     (New RibbonCheckBox())
                 CType(CType(Menu1.Items.Last(),  _
    RibbonMenu).Items.Last(), RibbonCheckBox).Label = productItem
                 AddHandler (CType(CType(Menu1.Items.Last(),  _
    RibbonMenu).Items.Last(), RibbonCheckBox).Click), AddressOf CheckBox_Click
    
             Next productItem
         Next orderItem
     End Sub
    
    
    
    
    private void PopulateSalesOrderInfo()
    {
        String[] tempArray = comboBox1.Text.Split(new Char[] { '|' });
        menu1.Items.Clear();
        string programFilesDir = Environment.GetFolderPath
            (Environment.SpecialFolder.ProgramFiles);
        AdventureWorks db = new AdventureWorks
            (programFilesDir + "\\Microsoft SQL Server\\" +
                "MSSQL.1\\MSSQL\\Data\\AdventureWorks_Data.mdf");
    
        var orderQuery = from orders in db.SalesOrderHeader
                         where orders.CustomerID.ToString() == tempArray[0]
                         select new { orders.SalesOrderID, 
                             orders.SalesOrderNumber };
    
        foreach (var orderItem in orderQuery)
        {
            RibbonMenu menu2 = new RibbonMenu();
            menu2.Dynamic = true;
            menu1.Items.Add(menu2);
            ((RibbonMenu)menu1.Items.Last()).Label = 
                orderItem.SalesOrderNumber.ToString();
            ((RibbonMenu)menu1.Items.Last()).Tag = 
                orderItem.SalesOrderID;
    
            var productQuery = from orderDetail in db.SalesOrderDetail
                               join product in db.Product on 
                                   orderDetail.ProductID 
                               equals product.ProductID
                               where orderDetail.SalesOrderID == 
                                   orderItem.SalesOrderID
                               select new { product.Name };
    
            foreach (var productItem in productQuery)
            {
                ((RibbonMenu)menu1.Items.Last()).Items.Add
                    (new RibbonCheckBox());
                ((RibbonCheckBox)((RibbonMenu)menu1.Items.Last()).
                    Items.Last()).Label = productItem.Name;
                ((RibbonCheckBox)((RibbonMenu)menu1.Items.Last()).
                    Items.Last()).Click 
                    += new EventHandler<RibbonControlEventArgs>(checkBox_Click);
            }
    
        }
    }
    
  9. 在 [方案總管] 中,按兩下功能區程式碼檔。

    功能區設計工具隨即開啟。

  10. 在功能區設計工具中,按兩下 [Customers] 下拉式方塊。

    功能區程式碼檔案會在程式碼編輯器中開啟,並會出現 ComboBox1_TextChanged 事件處理常式。

  11. 以下列程式碼取代 ComboBox1_TextChanged 事件處理常式。這個程式碼會執行下列工作:

    • 呼叫 PopulateSalesOrderInfo Helper 方法。此方法會以選取之客戶相關的銷售訂單來更新 [Products Purchased] 功能表。

    • 呼叫 PopulateMailItem Helper 方法。此方法會填入新郵件的 Microsoft.Office.Interop.Outlook.MailItem.ToMicrosoft.Office.Interop.Outlook.MailItem.SubjectMicrosoft.Office.Interop.Outlook.MailItem.Body 欄位。

    Private Sub ComboBox1_TextChanged(ByVal sender As System.Object, _
        ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) _
            Handles ComboBox1.TextChanged
        PopulateSalesOrderInfo()
        PopulateMailItem(ComboBox1.Text)
    End Sub
    
    private void comboBox1_TextChanged(object sender, 
        RibbonControlEventArgs e)
    {
        PopulateSalesOrderInfo();
        PopulateMailItem(comboBox1.Text);
    }
    
  12. 將下列程式碼加入至 CustomerRibbon 類別。此程式碼會將選取產品的名稱加入至新郵件的 Microsoft.Office.Interop.Outlook.MailItem.Body 欄位。

    Private Sub CheckBox_Click(ByVal sender As System.Object, _
        ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs)
        Dim application As Outlook.Application = Globals.ThisAddIn.Application
        Dim inspector As Outlook.Inspector = application.ActiveInspector()
        Dim myMailItem As Outlook.MailItem = CType(inspector.CurrentItem,  _
            Outlook.MailItem)
        Dim myCheckBox As RibbonCheckBox = CType(sender, RibbonCheckBox)
        myMailItem.Subject = "Following up on your order"
        myMailItem.Body = myMailItem.Body + ControlChars.Lf + "* " _
            + myCheckBox.Label
    End Sub
    
    private void checkBox_Click(object sender, RibbonControlEventArgs e)
    {
        Outlook.Application application = Globals.ThisAddIn.Application;
        Outlook.Inspector inspector = application.ActiveInspector();
        Outlook.MailItem myMailItem = (Outlook.MailItem)inspector.CurrentItem;
        RibbonCheckBox myCheckBox = (RibbonCheckBox)sender;
        myMailItem.Subject = "Following up on your order";
        myMailItem.Body = myMailItem.Body + "\n" + "* " + myCheckBox.Label;
    }
    
  13. 將下列程式碼加入至 CustomerRibbon 類別。這個程式碼會執行下列工作:

    • 使用目前選取之客戶的電子郵件地址來填入新郵件的 Microsoft.Office.Interop.Outlook.MailItem.To 行。

    • 將文字加入至新郵件的 Microsoft.Office.Interop.Outlook.MailItem.SubjectMicrosoft.Office.Interop.Outlook.MailItem.Body 欄位。

    Private Sub PopulateMailItem(ByVal addressToLine As String)
        Dim application As Outlook.Application = Globals.ThisAddIn.Application
        Dim inspector As Outlook.Inspector = application.ActiveInspector()
        Dim myMailItem As Outlook.MailItem = _
            CType(inspector.CurrentItem, Outlook.MailItem)
    
        myMailItem.To = ""
        Dim tempArray As [String]() = addressToLine.Split(New [Char]() {"|"c})
        myMailItem.To = tempArray(1) + "@example.com"
        myMailItem.Subject = "Following up on your order"
        myMailItem.Body = "Hello " + tempArray(1) + ","
        myMailItem.Body = myMailItem.Body + ControlChars.Lf + _
            "We would like to get your " + _
        "feedback on the following products that you recently ordered: "
    End Sub
    
    private void PopulateMailItem(string addressToLine)
    {
        Outlook.Application application = Globals.ThisAddIn.Application;
        Outlook.Inspector inspector = application.ActiveInspector();
        Outlook.MailItem myMailItem = (Outlook.MailItem)inspector.CurrentItem;
    
        myMailItem.To = "";
        String[] tempArray = addressToLine.Split(new Char[] { '|' });
        myMailItem.To = tempArray[1] + "@example.com";
        myMailItem.Subject = "Following up on your order";
        myMailItem.Body = "Hello " + tempArray[1] + ",";
        myMailItem.Body = myMailItem.Body + "\n" + 
            "We would like to get your " + 
                "feedback on the following products that you recently ordered: ";
    }
    

測試自訂群組中的控制項

當您在 Outlook 中開啟新郵件表單時,名為 [Customer Purchases] 的自訂群組會出現在功能區的 [訊息] 索引標籤中。

若要建立客戶的後續電子郵件訊息,請先選取客戶,再選取客戶所購買的產品。[Customer Purchases] 群組中的控制項會在執行階段使用 AdventureWorks 資料庫的資料進行更新。

若要測試自訂群組中的控制項

  1. 請按 F5 執行您的專案。

    Outlook 隨即啟動。

  2. 在 Outlook 的 [檔案] 功能表上,指向 [新增],然後按一下 [郵件]。

    這時會發生下列動作:

    • 新的郵件偵測器視窗會開啟。

    • 在功能區的 [訊息] 索引標籤中,[Customer Purchases] 群組會出現在 [剪貼簿] 群組之前。

    • 群組中的 [Customers] 下拉式方塊會以 AdventureWorks 資料庫中的客戶名稱進行更新。

  3. 在功能區 [訊息] 索引標籤的 [Customer Purchases] 群組中,從 [Customers] 下拉式方塊中選取客戶。

    這時會發生下列動作:

    • [Products Purchased] 功能表會隨著代表該客戶每筆銷售訂單的功能表進行更新。

    • 每個銷售訂單功能表會隨著代表客戶購買的產品的核取方塊進行更新。

    • 選取的客戶電子郵件地址會加入至郵件的 [收件者] 行,並在郵件的主旨跟本文中填入文字。

  4. 按一下 [Products Purchases] 功能表,指向任何銷售訂單,然後按一下銷售訂單中的產品。

    產品名稱會加入至郵件的本文中。

後續步驟

您可以透過下列主題,進一步了解自訂 Office UI 的方式:

請參閱

工作

HOW TO:開始自訂功能區

逐步解說:使用功能區設計工具建立自訂的索引標籤

HOW TO:變更功能區索引標籤的順序

HOW TO:自訂內建索引標籤

HOW TO:自訂 Microsoft Office 功能表

HOW TO:將功能區設計工具的功能區匯出到功能區 XML

HOW TO:顯示增益集使用者介面錯誤

概念

在執行階段存取功能區

功能區概觀

功能區設計工具

功能區物件模型概觀

自訂 Outlook 的功能區