在OFFICE2013及之后,使用了单文档界面技术,不同于以往版本可以共享任务空格、功能区。所以当开发任务窗格时,需要考虑到每一个工作薄都关联一个任务窗格。
背景介绍
单文档界面摘录官方定义如下: 对 Excel 2013 中的单文档界面 (SDI) 进行更改对可编程性具有一定影响。SDI 意味着每个工作簿都将有其自己的顶级应用程序窗口,并将有自己的相应功能区。
带来的好处是不同工作薄可以精细控制不同的显示,例如工作薄A,显示功能区Tab1,工作薄B显示功能区Tab2,区分对待不同文档所使用的功能。
带来的不便之处就是要每个文档都要考虑关联对应的界面,特别是任务窗格。
具体代码实现
Excel催化剂插件也大量使用了任务窗格,为了让用户在作配置信息时,可以更灵活,不必每次都弹出一个窗体来配置,只有需要配置时,才转到任务窗格中配置,否则保留默认的配置,并且默认配置可以让用户在任务窗格上查看。
所以用了任务窗格,需要做版本兼容性,即区分Excel2013及之后的版本的SDI特性。
下面截取关键代码,以Excel工作薄的工作表导航功能为例,作简单解释
工作表导航任务窗格
先初始化字典变量
代码语言:javascript复制 private static void InialTaskPanel()
{
Utilities.TaskPanelUtility.CustomTaskPanesOfWorksheetNavigation = new Dictionary<int, Microsoft.Office.Tools.CustomTaskPane>();
Utilities.TaskPanelUtility.UscWorksheetNavigations = new Dictionary<int, UscWorksheetNavigation>();
}
根据不同版本的Excel启用不同方法
代码语言:javascript复制 private void tgbShowActionPanel_Click(object sender, RibbonControlEventArgs e)
{
RibbonToggleButton tgb = sender as RibbonToggleButton;
try
{
if (Single.Parse(Common.ExcelApp.Version) >= 15)
{
WorksheetNavigate.ShowCustomTaskPanelOfWorksheetNavigationOfExcel2013(tgb.Checked);
}
else
{
WorksheetNavigate.ShowCustomTaskPanelOfWorksheetNavigationOfExcel2010(tgb.Checked);
}
//将工作表导航的显示状态保存起来
Properties.Settings.Default.IsPaneVisible = tgb.Checked;
Properties.Settings.Default.Save();
}
catch (Exception ex)
{
Common.OutMsgError(ex);
}
}
重点是2013版的方法,关键之处是拿到当前的活动窗体的句柄,通过字典查找是否已经创建过,没创建就新建,新建完要把它句柄存入到字典中。
代码语言:javascript复制 public static void ShowCustomTaskPanelOfWorksheetNavigationOfExcel2013(bool isPaneVisible)
{
int hwndCustomTaskPane = Common.ExcelApp.ActiveWindow.Hwnd;
Microsoft.Office.Tools.CustomTaskPane activeCustomTaskPane;
Utilities.TaskPanelUtility.CustomTaskPanesOfWorksheetNavigation.TryGetValue(hwndCustomTaskPane, out activeCustomTaskPane);
if (activeCustomTaskPane == null)
{
UscWorksheetNavigation uscWorksheetNavigation = new UscWorksheetNavigation();
activeCustomTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(uscWorksheetNavigation, "工作表导航", Globals.ThisAddIn.Application.ActiveWindow);
activeCustomTaskPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionLeft;
activeCustomTaskPane.Width = 300;
activeCustomTaskPane.VisibleChanged = ActiveCustomTaskPane_VisibleChanged;
activeCustomTaskPane.Visible = isPaneVisible;
Utilities.TaskPanelUtility.CustomTaskPanesOfWorksheetNavigation.Add(hwndCustomTaskPane, activeCustomTaskPane);
Utilities.TaskPanelUtility.UscWorksheetNavigations.Add(hwndCustomTaskPane, uscWorksheetNavigation);
}
else
{
activeCustomTaskPane.Visible = isPaneVisible;
if (isPaneVisible)
{
Utilities.TaskPanelUtility.UscWorksheetNavigations[hwndCustomTaskPane].ReLoadWorksheetName();
}
}
}
因工作表导航,每切换一次工作薄,都要更新下工作表清单,所以订阅了一个窗体切换事件,其他场景可能不必这样做,只需订阅个打开文件事件即可。
代码语言:javascript复制 private void ExcelApp_WindowActivate(Excel.Workbook Wb, Excel.Window Wn)
{
try
{
if (Common.ExcelApp.ActiveWorkbook.ProtectStructure == false)
{
bool isPaneVisible = Properties.Settings.Default.IsPaneVisible;
if (Single.Parse(Common.ExcelApp.Version) >= 15)
{
int hwndCustomTaskPane = this.Application.ActiveWindow.Hwnd;
WorksheetNavigate.ShowCustomTaskPanelOfWorksheetNavigationOfExcel2013(isPaneVisible);
}
else
{
WorksheetNavigate.ShowCustomTaskPanelOfWorksheetNavigationOfExcel2010(isPaneVisible);
}
}
}
catch (Exception)
{
}
}
其他的非关键代码,自己把握如何写就行,笔者写代码也有限,只能抛砖引玉了。
结语
通过直接的源代码讲解,希望对Excel开发的朋友们可以带来一些帮助,具体原理之外的东西,可自由发挥。