C#定制Excel界面并实现与数据库交互的方法
作者:JackWang-CUMT 发布时间:2024-01-25 13:13:24
Excel是微软办公套装软件的一个重要的组成部分,它可以进行各种数据的处理、统计分析和辅助决策操作,广泛地应用于管理、统计财经、金融等众多领域。(另外,Excel还是伦敦一所会展中心的名称)。.NET可以创建Excel Add-In对Excel进行功能扩展,这些扩展的功能包括自定义用户函数,自定义UI,与数据库进行数据交互等。
一 主要的Excel开发方式
1 VBA
VBA是一种Visual Basic的宏语言,它是最早的Office提供定制化的一种解决方案,VBA是VB的一个子集,和Visual Basic不同,VBA是一种宿主型语言,无论是专业的开发人员,还是刚入门的非开发人员,都可以利用VBA完成简单或复杂的需求。
2 Excel Addin
Excel Addin,就像Visual Studio外接插件一样,也可以使用一些技术为Office开发一些插件。对VBA的一些问题,一些专业的开发人员,可以使用 VisualBasic或者VisualC++等工具来引用Office的一些dll,来针对Office进行开发。开发的时候将dll注册为com组 件,并在注册表里面进行注册,这样就可以在Excel里直接调用这些插件。
3 VSTO (Visual Studio Tools for Office)
VSTO主要是对Office的一些dll进行了.NET封装,使得我们可以使用.NET上的语言来方便的对Office的一些方法进行调用。所 以,Office开发跨入了一个新的时代,开发人员可以使用更加高级的语言和熟悉的技术来更容易的进行Office开发。 对于企业及的应用和开发,VSTO或许是首要选择,他极大地扩展了Office应用程序的能力,使用.NET平台支持的编程语言,能够直接访问.NET上面众多的类库。具有较好的安全机制。简化了Office插件的开发和部署。
4 XLL
XLL是Excel的一种外接应用程序,他使用C和C++开发,程序通过调用Excel暴漏的C接口来实现扩展功能。这种方式开发的应用程序效率高,但是难度大,对开发者自身的要求较高。开源项目Excel-DNA就是使用XLL技术开发的,能够帮助.NET 开发人员来极大地简化RTD函数,同步、异步UDF函数的编写和开发。
5 OpenXML
如果用户没有安装Excel应用程序,或者在服务器端需要动态生成Excel文件的时候。我们可能需要直接读取或者生成Excel文件,这种情况下,如果要对Excel文件进行各种定制化开发的话,建议使用OpenXML。NPOI开源项目可以直接读写Excel文件,而且兼容多个版本。
二 使用Excel Add-In构建扩展
开发环境: 操作系统为Windows Server 2008R2 x64;Excel为Excel 2010 x64;开发工具为Visual Studio 2012旗舰版x64;数据库为SQL Server 2008R2 x64.
1 程序结构
用Visual Studio 2012新建一个ExcelAddInDemo的Excel Add-In项目,并添加若干文件,程序结构如下图:
其中,RibbonAddIn可以定制2010的UI面板,SqlHelper.cs是一个简单的数据库访问帮助类,UClog.cs,UCPaneLeft.cs,UCTaskGrid.cs,UCTaskPane.cs都为添加的自定义控件,并通过程序添加到EXCEL界面中.运行起来的界面如下:
程序可以通过在Excel界面中输入ID,First,Last,Email的值(对应标签的后一个单元格),单击用户列表面板上的保存按钮,将数据保存到数据库中.
2 RibbonAddIn设计
我们通过RibbonAddIn.cs给Excel的Ribbon添加了一个名为CUMT的插件.RibbonAddIn面板可以通过工具条控件方便的拖放到设计界面上.RibbonAddIn.cs的属性设置如下图所示:
后台代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Tools.Ribbon;
namespace ExcelAddInDemo
{
public partial class RibbonAddIn
{
private void RibbonAddIn_Load(object sender, RibbonUIEventArgs e)
{
}
private void btnAbout_Click(object sender, RibbonControlEventArgs e)
{
System.Windows.Forms.MessageBox.Show("JackWangCUMT!");
}
private void btnShow_Click(object sender, RibbonControlEventArgs e)
{
if (Globals.ThisAddIn._MyCustomTaskPane != null)
{
Globals.ThisAddIn._MyCustomTaskPane.Visible = true;
}
}
private void btnHide_Click(object sender, RibbonControlEventArgs e)
{
if (Globals.ThisAddIn._MyCustomTaskPane != null)
{
Globals.ThisAddIn._MyCustomTaskPane.Visible = false;
}
}
}
}
3 ThisAddIn逻辑编写
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Excel = Microsoft.Office.Interop.Excel;
namespace ExcelAddInDemo
{
using Microsoft.Office.Tools;
public partial class ThisAddIn
{
public CustomTaskPane _MyCustomTaskPane = null;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
UCTaskPane taskPane = new UCTaskPane();
_MyCustomTaskPane = this.CustomTaskPanes.Add(taskPane, "我的任务面板");
_MyCustomTaskPane.Width = ;//height有问题,此处width ==height
_MyCustomTaskPane.Visible = true;
_MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionTop;
UCPaneLeft panLeft = new UCPaneLeft();
_MyCustomTaskPane = this.CustomTaskPanes.Add(panLeft, "组织");
_MyCustomTaskPane.Width = ;
_MyCustomTaskPane.Visible = true;
_MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionLeft;
UCTaskGrid panRight = new UCTaskGrid();
_MyCustomTaskPane = this.CustomTaskPanes.Add(panRight, "用户列表");
_MyCustomTaskPane.Width = ;
_MyCustomTaskPane.Visible = true;
_MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionRight;
UCLog panLog = new UCLog();
_MyCustomTaskPane = this.CustomTaskPanes.Add(panLog, "日志列表");
_MyCustomTaskPane.Width = ;
_MyCustomTaskPane.Visible = true;
_MyCustomTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionBottom;
//Hook into the workbook open event
//This is because Office doesn't always have a document ready when this method is run
this.Application.WorkbookActivate += Application_WorkbookActivate;
//test
//this.Application.SheetSelectionChange += Application_SheetSelectionChange;
}
void Application_SheetSelectionChange(object Sh, Excel.Range Target)
{
if (this.Application != null)
{
this.Application.Caption = this.Application.ActiveCell.Address.ToString();//$A$
//+ this.Application.ActiveCell.AddressLocal.ToString();//$A$
//this.Application.ActiveCell.Formula = "=sum(+)";
}
}
void Application_WorkbookActivate(Excel.Workbook Wb)
{
//using Microsoft.Office.Tools.Excel 和 using Microsoft.Office.Interop.Excel 都有worksheet等,容易混淆
//string path = this.Application.ActiveWorkbook.FullName;
Excel._Worksheet ws = (Excel._Worksheet)this.Application.ActiveWorkbook.ActiveSheet;
ws.Cells[, ] = "ID";
//如何设置只读等有待研究
int r=,c=;
//((Excel.Range)ws.Cells[r, c]).NumberFormat = format;
((Excel.Range)ws.Cells[r, c]).Value = "ID";
((Excel.Range)ws.Cells[r, c]).Interior.Color =System.Drawing. ColorTranslator.ToOle(System.Drawing.Color.Red);
//((Excel.Range)ws.Cells[r, c]).Style.Name = "Normal";
((Excel.Range)ws.Cells[r, c]).Style.Font.Bold = true;
#region format
((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Bold = true;
((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Italic = true;
((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Color = System.Drawing.Color.FromArgb(, , ).ToArgb();
((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Name = "Calibri";
((Microsoft.Office.Interop.Excel.Range)ws.get_Range("A", "E")).Font.Size = ;
//border
Excel.Range range = ((Microsoft.Office.Interop.Excel.Range)ws.get_Range("B", "E"));
Excel. Borders border = range.Borders;
border[Excel.XlBordersIndex.xlEdgeBottom].LineStyle =Excel. XlLineStyle.xlContinuous;
border.Weight = d;
border[Excel.XlBordersIndex.xlEdgeTop].LineStyle = Excel.XlLineStyle.xlContinuous;
border[Excel.XlBordersIndex.xlEdgeLeft].LineStyle = Excel.XlLineStyle.xlContinuous;
border[Excel.XlBordersIndex.xlEdgeRight].LineStyle = Excel.XlLineStyle.xlContinuous;
#endregion
ws.Cells[, ] = "First";
ws.Cells[, ] = "Last";
ws.Cells[, ] = "Email";
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO 生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
ThisAddIn_Startup事件中,初始化四个面板,并对其基本属性进行设置,停靠在上的面板我设置其Height无效,改成Width后其效果和Height预期的一样(不知道这个底层开发人员是怎么想的,哈哈!)另外 Excel._Worksheet ws = (Excel._Worksheet)this.Application.ActiveWorkbook.ActiveSheet;是非常关键的一句,我这里足足折腾了很久,原因是using Microsoft.Office.Tools.Excel 和 using Microsoft.Office.Interop.Excel 都有worksheet元素,结构混淆了,运行时老是获取不到Excel的ActiveWorkbook.
4 UCTaskGrid设计
UCTaskGrid是一个用户控件,包含一个工具条和一个dataGridView1控件,其设计界面如下:
后台代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ExcelAddInDemo
{
using Excel = Microsoft.Office.Interop.Excel;
public partial class UCTaskGrid : UserControl
{
public UCTaskGrid()
{
InitializeComponent();
}
private void UCTaskGrid_Load(object sender, EventArgs e)
{
//load data
System.Data.DataTable dt = SqlHelper.getDateTable("select * from ACT_ID_USER", null);
this.dataGridView.DataSource = dt;
}
private void 保存SToolStripButton_Click(object sender, EventArgs e)
{
//核心代码,获取当前的worksheet
Excel._Worksheet ws = (Excel._Worksheet)Globals.ThisAddIn.Application.ActiveWorkbook.ActiveSheet;
string name = ws.Name;
string ID = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString();
string First = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString();
string Last = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString();
string Email = ((string)(ws.Cells[, ] as Excel.Range).Value).ToString();
string sql = string.Format("insert into ACT_ID_USER ([ID_],[FIRST_],[LAST_],[EMAIL_]) values('{}','{}','{}','{}')", ID, First, Last, Email);
int rows= SqlHelper.ExecuteNonQuery(SqlHelper.ConnectionStringLocalTransaction, System.Data.CommandType.Text,sql,null);
if (rows == )
{
System.Windows.Forms.MessageBox.Show("saved");
}
else
{
System.Windows.Forms.MessageBox.Show("error");
}
}
private void 打开OToolStripButton_Click(object sender, EventArgs e)
{
//refresh
System.Data.DataTable dt = SqlHelper.getDateTable("select * from ACT_ID_USER", null);
this.dataGridView.DataSource = dt;
}
}
}
5 Add-In强签名
通过设置程序的属性中的签名页,让VS自动生成一个签名即可(需设置密码)
三 最终效果演示
为了直观的展示,看下面的动画:
四 猜想 Excel Service
现在功能很强大的Excel服务器,其中一个亮点就是在Excel中进行界面设计和数据操作,然后就数据持久化到数据库中,那么我的猜想是,能不能通过AddIn的方式实现一个excel service功能呢,将界面设计序列化保存到数据库中,并给一个路径(唯一),但用户单击菜单(确定了路径)后将界面设计呈现到excel中,然后用户操作完成后,通过后台程序将数据库保存到数据库中.
猜你喜欢
- 像素是计算机视觉中图像的重要属性。它们是表示图像 * 定空间中光的颜色强度的数值,是图像中数据的最小单位。图像中的像素总数是高度、宽度和通道的
- 一、功能简述正是微博如火如荼的时节,其中各个微博的分享功能是网站推广产品的好东东啊,此时如何方便快捷的使用微博的分享功能就显得比较重要了。我
- Vue如何配置根目录@首先:@是在路径访问时使用的,为了减少层级引用。@这是webpack设置的路径别名,默认指向src。旧版本在build
- 一、字符串方法1.字符串的分割s.split() 默认是按照空格分割s.split(',') 按照逗号分割(返回的是一个列表
- 这个符合设计标准的三 级向上弹出菜单,纯css代码控制,没有使用javascript脚本,绿色环保,呵呵。兼容性应该更好。截图:<!D
- 一次性读取csv文件内所有行的数据<?php $file = fopen('windows_2011_s.csv',&
- 近期,我做了一个娱乐门户的投票系统,也是被刷票搞的焦头烂额,一切可用的方法都用了。但都不是太理想,最终,琢磨出来了下面的方法,我做成了流程图
- 首先在文件夹中添加_init_.py文件,即使是空文件也可以,多层文件夹,每层文件夹中都要添加。比如我要import,a文件夹中,b文件夹下
- 方法1: 用SET PASSWORD命令 首先登录MySQL。 格式:mysql> set password for 用户名@loca
- python现在的版本,主要是python2和python3两个大版本,这两个版本有很大的不同。当我们在自己电脑上同时安装了python2.
- 有这样一个文本文件,内容有多行如下,数量不定。Lif(__amscript_cd("www.jb51.net")){__
- Java 正则表达式正则表达式定义了字符串的模式。正则表达式可以用来搜索、编辑或处理文本。正则表达式并不仅限于某一种语言,但是在每种语言中有
- 本文为大家分享了MySQL免安装版(zip)安装配置教程,供大家参考,具体内容如下1.MySQL官网下载2.将下载的解压到D:\mysql-
- Sql server中常用的几个数据类型: binary 固定长度的二进制数据,其最大长度为 8,000 个字节。 varbinary 可变
- 在设计主键的时候往往需要考虑以下几点: 1.无意义性:此处无意义是从用户的角度来定义的。这种无意义在一定程度上也会减少数据库的信息冗余。常常
- 原理 :1、js动态创建DIV,指定CLASS类设置不同的背景图样式显示不同的雪花效果。2、js获取创建的DIV并改变其top属性值,当下落
- 第一步:首先定义一个视图函数,用于提供数据,实现每页显示数据个数,返回每页请求数据from django.shortcuts import
- 一、Set 集合类型Set 集合类型 (交差并补) 特点 :无序 , 自动去重集合用{}表示,元素间用逗号分隔建立集合类型用{}或set()
- 前言网上很多例子都说cv2.minAreaRect函数的输出的角度范围在[-90,0],但是实测输出范围在[0,90]。再进行调研,确定为o
- 前言:转眼距离上篇JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)已有好几个月了,今天打算将它捡起来,发现好久不用