演练:在运行时在应用程序级项目中向工作表中添加控件

更新: 2008 年 7 月

适用于

本主题中的信息仅适用于指定的 Visual Studio Tools for Office 项目和 Microsoft Office 版本。

项目类型

  • 应用程序级项目

Microsoft Office 版本

  • Excel 2007

有关更多信息,请参见按应用程序和项目类型提供的功能

可以使用 Excel 2007 外接程序向任何打开的工作表中添加控件。本演练演示如何使用功能区让用户可以向工作表中添加 ButtonNamedRangeListObject

有关信息,请参见在运行时向 Office 文档添加控件

本演练阐释以下任务:

  • 提供用于向工作表中添加控件的用户界面 (UI)。

  • 向工作表中添加控件。

  • 从工作表中移除控件。

Cc442817.alert_note(zh-cn,VS.90).gif说明:

对于在以下说明中使用的某些 Visual Studio 用户界面元素,您的计算机可能会显示不同的名称或位置。这些元素取决于您使用的 Visual Studio 版本及设置。有关更多信息,请参见Visual Studio 设置

先决条件

您需要以下组件来完成本演练:

  • Visual Studio Tools for Office(Visual Studio 2008 专业版 和 Visual Studio Team System 的可选组件)。

  • Visual Studio 2008 Service Pack 1 (SP1)。

  • Microsoft Office Excel 2007。

创建新的 Excel 外接程序项目

从创建 Excel 2007 外接程序项目开始。

创建新的 Excel 外接程序项目

  1. 在 Visual Studio 中,创建一个名为“ExcelDynamicControls”的 Excel 2007 外接程序项目。

  2. 在“新建项目”对话框中选择“创建解决方案的目录”。

  3. 将此项目保存到任意位置。

    有关更多信息,请参见如何:创建 Visual Studio Tools for Office 项目

提供用于向工作表中添加控件的用户界面

向 Excel 2007 功能区中添加自定义选项卡。用户可以选中该选项卡上的复选框,以向工作表中添加控件。

提供用于向工作表中添加控件的用户界面

  1. 在“项目”菜单上单击“添加新项”。

  2. 在“添加新项”对话框中,选择“功能区(可视化设计器)”,再单击“添加”。

    名为 Ribbon1.cs 或 Ribbon1.vb 的文件将在功能区设计器中打开,并显示一个默认选项卡和组。

  3. 从“工具箱”的“Office 功能区控件”选项卡中将 CheckBox 控件拖到“group1”上。

  4. 单击“CheckBox1”将它选中。

  5. 在“属性”窗口中,更改下列属性。

    属性

    Name

    Button

    Label

    Button

  6. 向“group1”中添加第二个复选框,然后更改以下属性。

    属性

    Name

    NamedRange

    Label

    NamedRange

  7. 向“group1”中添加第三个复选框,然后更改以下属性。

    属性

    Name

    ListObject

    Label

    ListObject

将控件添加到工作表

托管控件只能添加到充当容器的宿主项。由于外接程序项目可以处理任何打开的工作簿,因此外接程序在添加控件之前会将工作表转换为宿主项,或获取现有的宿主项。将代码添加到每个控件的 Click 事件处理程序,以生成基于打开的工作表的 Worksheet 宿主项。然后,在工作表中的当前选定内容处添加 ButtonNamedRangeListObject

向工作表中添加控件

  1. 在功能区设计器中双击“Button”。

    “Button”复选框的 Click 事件处理程序在代码编辑器中打开。

  2. 用下面的代码替换 Button_Click 事件处理程序。

    此代码使用 GetVstoObject 方法获取表示工作簿中的第一个工作表的宿主项,然后将 Button 控件添加到当前选定的单元格。

    Private Sub Button_Click(ByVal sender As System.Object, _
        ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) _
            Handles Button.Click
        Dim worksheet = CType(Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets(1),  _
            Excel.Worksheet).GetVstoObject()
        Dim buttonName As String = "MyButton"
    
        If CType(sender, RibbonCheckBox).Checked Then
            Dim selection As Excel.Range = Globals.ThisAddIn.Application.Selection
            If Not (selection Is Nothing) Then
                Dim button As New Microsoft.Office.Tools.Excel.Controls.Button()
                worksheet.Controls.AddControl(button, selection, buttonName)
            End If
        Else
            worksheet.Controls.Remove(buttonName)
        End If
    End Sub
    
    private void Button_Click(object sender, RibbonControlEventArgs e)
    {
        Worksheet worksheet = ((Excel.Worksheet)
            Globals.ThisAddIn.Application.
                ActiveWorkbook.Worksheets[1]).GetVstoObject();
        string buttonName = "MyButton";
    
        if (((RibbonCheckBox)sender).Checked)
        {
            Excel.Range selection =
                Globals.ThisAddIn.Application.Selection as Excel.Range;
            if (selection != null)
            {
                Microsoft.Office.Tools.Excel.Controls.Button button =
                    new Microsoft.Office.Tools.Excel.Controls.Button();
                worksheet.Controls.AddControl(button, selection, buttonName);
            }
        }
        else
        {
            worksheet.Controls.Remove(buttonName);
        }
    }
    
  3. 在“解决方案资源管理器”中,选择 Ribbon1.cs 或 Ribbon1.vb。

  4. 在“视图”菜单上,单击“设计器”。

  5. 在功能区设计器中双击“NamedRange”。

  6. 用下面的代码替换 NamedRange_Click 事件处理程序。

    此代码使用 GetVstoObject 方法获取表示工作簿中的第一个工作表的宿主项,然后为当前选定的一个或多个单元格定义 NamedRange 控件。

    Private Sub NamedRange_Click(ByVal sender As System.Object, _
        ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) _
            Handles NamedRange.Click
        Dim worksheet = CType(Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets(1),  _
            Excel.Worksheet).GetVstoObject()
        Dim rangeName As String = "MyNamedRange"
    
        If CType(sender, RibbonCheckBox).Checked Then
            Dim selection As Excel.Range = Globals.ThisAddIn.Application.Selection
            If Not (selection Is Nothing) Then
                Dim namedRange As NamedRange = _
                    worksheet.Controls.AddNamedRange(selection, rangeName)
            End If
        Else
            worksheet.Controls.Remove(rangeName)
        End If
    End Sub
    
    private void NamedRange_Click(object sender, RibbonControlEventArgs e)
    {
        Worksheet worksheet =
              ((Excel.Worksheet)Globals.ThisAddIn.Application.ActiveWorkbook.
                  Worksheets[1]).GetVstoObject();
        string Name = "MyNamedRange";
    
        if (((RibbonCheckBox)sender).Checked)
        {
            Excel.Range selection =
                Globals.ThisAddIn.Application.Selection as Excel.Range;
            if (selection != null)
            {
                worksheet.Controls.AddNamedRange(selection, Name);
            }
        }
        else
        {
            worksheet.Controls.Remove(Name);
        }
    }
    
  7. 在功能区设计器中双击“ListObject”。

  8. 用下面的代码替换 ListObject_Click 事件处理程序。

    此代码使用 GetVstoObject 方法获取表示工作簿中的第一个工作表的宿主项,然后为当前选定的一个或多个单元格定义 ListObject

    Private Sub ListObject_Click(ByVal sender As System.Object, _
        ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) _
            Handles ListObject.Click
        Dim worksheet = CType(Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets(1),  _
            Excel.Worksheet).GetVstoObject()
        Dim listObjectName As String = "MyListObject"
    
        If CType(sender, RibbonCheckBox).Checked Then
            Dim selection As Excel.Range = _
                Globals.ThisAddIn.Application.Selection
            If Not (selection Is Nothing) Then
                worksheet.Controls.AddListObject(selection, listObjectName)
            End If
        Else
            worksheet.Controls.Remove(listObjectName)
        End If
    End Sub
    
    private void ListObject_Click(object sender, RibbonControlEventArgs e)
    {
        Worksheet worksheet =
              ((Excel.Worksheet)Globals.ThisAddIn.Application.ActiveWorkbook.
                  Worksheets[1]).GetVstoObject();
        string listObjectName = "MyListObject";
    
        if (((RibbonCheckBox)sender).Checked)
        {
            Excel.Range selection =
                Globals.ThisAddIn.Application.Selection as Excel.Range;
            if (selection != null)
            {
                worksheet.Controls.AddListObject(selection, listObjectName);
            }
        }
        else
        {
            worksheet.Controls.Remove(listObjectName);
        }
    }
    
  9. 将以下 using 语句添加到功能区代码文件顶部。

    Imports Excel = Microsoft.Office.Interop.Excel
    Imports Microsoft.Office.Tools.Excel
    Imports Microsoft.Office.Tools.Excel.Extensions
    
    using Excel = Microsoft.Office.Interop.Excel;
    using Microsoft.Office.Tools.Excel;
    using Microsoft.Office.Tools.Excel.Extensions;
    

从工作表中移除控件

保存并关闭工作表后,控件不会保留。您应该在保存工作表之前,以编程方式移除所有生成的 Windows 窗体控件,否则在再次打开工作簿时,将只显示控件的轮廓。将代码添加到 WorkbookBeforeSave 事件,该事件将 Windows 窗体控件从生成的宿主项的控件集合中移除。有关更多信息,请参见在 Office 文档中保存动态控件

从工作表中移除控件

  1. 在“解决方案资源管理器”中,选择 ThisAddIn.cs 或 ThisAddIn.vb。

  2. 在“视图”菜单上单击“代码”。

  3. 将下面的方法添加到 ThisAddIn 类中。此代码获取工作簿中的第一个工作表,然后使用 HasVstoObject 方法来检查该工作表是否具有生成的 Visual Studio Tools for Office 工作表对象。如果生成的工作表对象具有控件,此代码将获取该工作表对象,并循环访问控件集合,同时移除控件。

    Sub Application_WorkbookBeforeSave _
        (ByVal workbook As Microsoft.Office.Interop.Excel.Workbook, _
         ByVal SaveAsUI As Boolean, ByRef Cancel As Boolean) _
         Handles Application.WorkbookBeforeSave
    
        Dim worksheet As Excel.Worksheet = workbook.Worksheets(1)
        If worksheet.HasVstoObject() And worksheet.GetVstoObject().Controls.Count > 0 Then
            Dim vstoWorksheet As Worksheet = worksheet.GetVstoObject()
    
            While vstoWorksheet.Controls.Count > 0 
                Dim vstoControl As Object = vstoWorksheet.Controls(0) 
                vstoWorksheet.Controls.Remove(vstoControl) 
            End While
        End If
    End Sub
    
    void Application_WorkbookBeforeSave(Microsoft.Office.Interop.Excel.Workbook workbook, 
        bool SaveAsUI, ref bool Cancel)
    {
        Excel.Worksheet worksheet =
            workbook.Worksheets[1] as Excel.Worksheet;
    
        if (worksheet.HasVstoObject() && worksheet.GetVstoObject().Controls.Count > 0)
        {
            Worksheet vstoWorksheet = worksheet.GetVstoObject();
    
            while (vstoWorksheet.Controls.Count > 0)
            {
                object vstoControl = vstoWorksheet.Controls[0];
                vstoWorksheet.Controls.Remove(vstoControl);
            }
    
        }
    }
    
  4. 在 C# 中,必须为 WorkbookBeforeSave 事件创建事件处理程序。可以将此代码放在 ThisAddIn_Startup 方法中。有关创建事件处理程序的更多信息,请参见如何:使用 Visual Studio Tools for Office 创建事件处理程序。用下面的代码替换 ThisAddIn_Startup 方法。

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        this.Application.WorkbookBeforeSave += 
            new Microsoft.Office.Interop.Excel.AppEvents_WorkbookBeforeSaveEventHandler
                (Application_WorkbookBeforeSave);
    }
    

测试解决方案

通过在功能区的自定义选项卡中选择控件来向工作表中添加控件。保存工作表时,将移除这些控件。

测试解决方案。

  1. 按 F5 运行项目。

  2. 选择 Sheet1 中的任何单元格。

  3. 单击“外接程序”选项卡。

  4. 在“group1”组中,单击“Button”。

    一个按钮显示在所选单元格中。

  5. 选择 Sheet1 中的另一个单元格。

  6. 在“group1”组中,单击“NamedRange”。

    将为所选单元格定义一个命名区域。

  7. 选择 Sheet1 中的一系列单元格。

  8. 在“group1”组中,单击“ListObject”。

    将为所选单元格添加一个列表对象。

  9. 保存工作表。

    您添加到 Sheet1 的控件不再显示。

后续步骤

您可以从本主题中了解关于 Excel 2007 外接程序项目中的控件的更多信息:

请参见

概念

Excel 应用程序级外接程序开发

在 Excel 工作表中使用 Windows 窗体控件

NamedRange 控件

ListObject 控件

其他资源

Office 文档上的控件

Excel 宿主控件

修订记录

日期

修订历史记录

原因

2008 年 7 月

新增主题。

SP1 功能更改。