C# winform 可视化操作 Excel文件并读取数据

 

本人近期接到一个任务,要求开发一个可以操作和读取Excel文件的软件。

花了几天时间开发完成。本机跑的可以,兼容性还待检测。

 

解决方案:

 dsoframer.ocx  + Microsoft.Office.Interop.Excel

dsoframer.ocx 是用来可视化操作office文件的C#控件,Microsoft.Office.Interop.Excel 是用来操作和读取的控件。

 

效果图如下:

这个是可视化操作,导入excel文件,可以删除行,当然所有的excel操作都可以,已测试wps和Microsoft office 软件都可以正常读取和操作。导入数据是将excel数据读取到DataTable 中。

第一行和第一列是通过代码添加的,具体实现方式将在下面贴出来。

 

DataTable 读取到数据展示如下:

  

 

 

代码部分:

using System;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
using System.Data.OleDb;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace ReadExcel
{
    public partial class Form1 : Form
    {
        private AxDSOFramer.AxFramerControl m_axFramerControl = new AxDSOFramer.AxFramerControl();
        System.Data.DataTable dtEnd = new System.Data.DataTable();
        bool isOpenExcel = false;
        public Form1()
        {
            InitializeComponent();
        }


        #region 按钮事件
        private void button1_Click(object sender, EventArgs e)
        {
            //读取excel
            OpenFileDialog dia = new OpenFileDialog();
            dia.Filter = "公路计价文件(*.xls)|*.xls;*.xlsx";
            dia.FilterIndex = 0;
            dia.ShowDialog();
            if (string.IsNullOrEmpty(dia.FileName))
            {
                return;
            }
            if (isOpenExcel == true)//先关闭已打开的excel
            {
                try
                {
                    CloseFrom();
                }
                catch (Exception)
                {
                }
            }

            //复制到本地 因为快捷方式可以用,修改后可以保存,会导致修改源文件
            string tempFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TempFile");
            if (!System.IO.Directory.Exists(tempFile)) System.IO.Directory.CreateDirectory(tempFile);
            string tempExcelPath = Path.Combine(tempFile, "tempExcel" + Path.GetExtension(dia.FileName));
            System.IO.File.Copy(dia.FileName, tempExcelPath, true);

            try
            {

                //打开本地excel 
                Init(tempExcelPath);
                isOpenExcel = true;

                try
                {
                    //所有的sheet都应该增加
                    object documentExcel = m_axFramerControl.ActiveDocument;
                    //// 获取当前工作薄
                    Workbook workbook = (Microsoft.Office.Interop.Excel.Workbook)documentExcel;
                    foreach (Worksheet worksheet in workbook.Sheets)
                    {
                        if (worksheet != null)
                        {
                            int columnsint = worksheet.UsedRange.Cells.Columns.Count;//得到列数  
                            int rowsint = worksheet.UsedRange.Rows.Count; //得到行数
                            if (rowsint == 1) continue;
                            #region  增加行
                            Range range = (Range)worksheet.Rows[1, Type.Missing];
                            //object   Range.Insert(object   shift,   object   copyorigin);     
                            //shift:   Variant类型,可选。指定单元格的调整方式。可以为下列   XlInsertShiftDirection   常量之一:   
                            //xlShiftToRight   或   xlShiftDown。如果省略该参数,Microsoft   Excel   将根据区域形状确定调整方式。   
                            range.Insert(XlInsertShiftDirection.xlShiftDown, Type.Missing);

                            System.Data.DataTable dt = new System.Data.DataTable();
                            dt.Columns.Add("Name");
                            DataRow dr = dt.NewRow();
                            dr[0] = "姓名";
                            dt.Rows.Add(dr);
                            DataRow dr1 = dt.NewRow();
                            dr1[0] = "性别";
                            dt.Rows.Add(dr1);
                            DataRow dr2 = dt.NewRow();
                            dr2[0] = "年龄";
                            dt.Rows.Add(dr2);
                            DataRow dr3 = dt.NewRow();
                            dr3[0] = "地址";
                            dt.Rows.Add(dr3);
                            range = worksheet.get_Range("A1", ToName(columnsint - 1) + "1"); 
                            range.RowHeight = 30;
                            range.Font.Bold = true;
                            string strName = GetNameFromDt(dt);
                            //绑定下拉列表
                            range.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, strName, Type.Missing);//Name就是上面获取的列表
                            // range.Validation.Modify(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, Type.Missing, strName, Type.Missing);//单元格已设置数据有效性,只能用代码修改有效性;如果单元格未设置有效性,需要使用 Add 方法

                            // 填充值
                            worksheet.Cells[1, 1] = "姓名";
                            worksheet.Cells[1, 2] = "性别";
                            worksheet.Cells[1, 3] = "年龄";
                            worksheet.Cells[1, 4] = "地址";
                            #endregion

                            #region 增加列
                            Range xlsColumns = (Range)worksheet.Columns[1, Type.Missing];
                            xlsColumns.Insert(XlInsertShiftDirection.xlShiftToRight, Type.Missing);


                            System.Data.DataTable dtColumn = new System.Data.DataTable();
                            dtColumn.Columns.Add("Name");
                            DataRow drcol = dtColumn.NewRow();
                            drcol[0] = "有效行";
                            dtColumn.Rows.Add(drcol);
                            DataRow drcol1 = dtColumn.NewRow();
                            drcol1[0] = "无效行";
                            dtColumn.Rows.Add(drcol1);
                            strName = GetNameFromDt(dtColumn);

                            //绑定下拉列表
                            //xlsColumns = (Range)worksheet.Columns[1, Type.Missing];
                            xlsColumns = worksheet.get_Range("A2", "A"+ (rowsint+1).ToString());
                            xlsColumns.Validation.Add(XlDVType.xlValidateList, XlDVAlertStyle.xlValidAlertStop, XlFormatConditionOperator.xlBetween, strName, Type.Missing);//Name就是上面获取的列表
                            xlsColumns.ColumnWidth = 20;
                            // 填充值
                            xlsColumns.Value = "有效行";
                            #endregion
                            Range m_objRange = worksheet.get_Range("A1", Type.Missing);
                            m_objRange.Borders[XlBordersIndex.xlDiagonalDown].ColorIndex = XlColorIndex.xlColorIndexAutomatic;
                            m_objRange.Value = "           识别行\r\n  设置列";
                        }
                    }


                }
                catch (Exception ex)
                {

                    throw;
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("打开失败!" + ex.ToString());
            }
        }

        /// <summary>
        /// 读取쫽뻝
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            if (!isOpenExcel)
            {
                MessageBox.Show("未导入Excel文件!");
                return;
            }
            object documentExcel = m_axFramerControl.ActiveDocument;

            #region 保存本地读取方法 存在的问题是多个sheet 不知道读取哪个,下面的方法可以读取当前活动页
            ////另存为excel
            //string filePath = "F:\\111.xls";
            //m_axFramerControl.SaveAs(filePath, true);//另存为xls       

            ////读取excel 到datatable
            //System.Data.DataTable dt = GetDataFromExcel(filePath);
            #endregion

            try
            {
                //先保存本地,不然在修改中的单元格依然读取的是原数据
                m_axFramerControl.SaveAs(m_axFramerControl.DocumentFullName, true);//另存为xls  


                //// 获取当前工作薄
                Workbook workbook = (Microsoft.Office.Interop.Excel.Workbook)documentExcel;
                Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.ActiveSheet;

                if (worksheet != null)
                { // 取得总记录行数(包括标题列)
                    int rowsint = worksheet.UsedRange.Rows.Count; //得到行数
                    int columnsint = worksheet.UsedRange.Cells.Columns.Count;//得到列数
                    //取得数据范围区域 (标题列) 
                    Range rng1 = worksheet.Cells.get_Range("A1", ToName(columnsint - 1) + "1");   //item
                    object[,] arryItem = (object[,])rng1.Value2;
                    string[] tmp = new string[columnsint];
                    for (int i = 0; i < columnsint; i++)
                    {
                        if (arryItem[1, i + 1] == null)
                            continue;
                        tmp[i] = arryItem[1, i + 1].ToString();
                    }

                    Range mRange = worksheet.get_Range("A2", ToName(columnsint - 1) + rowsint);

                    object[,] mArray = (object[,])mRange.Formula;
                    string[,] myStrArr = new string[rowsint - 1, columnsint];
                    for (int i = 0; i < rowsint - 1; i++)
                    {
                        for (int j = 0; j < columnsint; j++)
                        {
                            myStrArr[i, j] = mArray[i + 1, j + 1].ToString();
                        }
                    }

                    dtEnd = ConvertToDataTable(tmp, myStrArr);
                    MessageBox.Show("读取成功!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("读取失败!" + ex.ToString());
            }


        }
        private void btn_deleteRow_Click(object sender, EventArgs e)
        {
            if (!isOpenExcel)
            {
                MessageBox.Show("未导入Excel文件!");
                return;
            }
            //先保存本地,不然在修改中的单元格依然读取的是原数据
            m_axFramerControl.SaveAs(m_axFramerControl.DocumentFullName, true);//另存为xls  

            object documentExcel = m_axFramerControl.ActiveDocument;

            Range excelRange = GetSelectionCell(documentExcel);
            if (excelRange == null)
            {
                MessageBox.Show("未选择单元格或行!");
                return;
            }
            excelRange.Select();
            excelRange.EntireRow.Delete(XlDeleteShiftDirection.xlShiftUp);

        }

        /// <summary>
        /// 显示数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            Form2 frm = new Form2(this.dtEnd);
            frm.ShowDialog();

        }
        #endregion


        #region AxFramerControl Excel 的加载

        //总的加载Excel方法
        private void Init(string _ExcelFilePath)
        {
            try
            {
                RegControl();

                if (!File.Exists(_ExcelFilePath))
                {
                    MessageBox.Show("文件不存在或未标识的文件格式!", "提示信息");
                    return;
                    //throw new ApplicationException("文件不存在或未标识的文件格式!");
                }

                AddAxFramerControl();//加载填充控件
                m_axFramerControl.Titlebar = false;//是否显示excel标题栏
                m_axFramerControl.Menubar = false;//是否显示excel的菜单栏
                m_axFramerControl.Toolbars = false;//是否显示excel的工具栏

                InitOfficeControl(_ExcelFilePath);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        //第二步:向panel填充AxFramerControl控件
        private void AddAxFramerControl()
        {
            try
            {
                this.panel1.Controls.Add(m_axFramerControl);
                m_axFramerControl.Dock = DockStyle.Fill;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                throw;
            }

        }

        //第一步:注册AxFramerControl
        public bool RegControl()
        {
            try
            {
                Assembly thisExe = Assembly.GetExecutingAssembly();
                System.IO.Stream myS = thisExe.GetManifestResourceStream("NameSpaceName.dsoframer.ocx");

                string sPath = System.AppDomain.CurrentDomain.BaseDirectory + @"\dsoframer.ocx";
                ProcessStartInfo psi = new ProcessStartInfo("regsvr32", "/s " + sPath);
                Process.Start(psi);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return true;
        }

        //下面这个方法是dso打开文件时需要的一个参数,代表office文件类型
        /// <summary>
        /// 根据后缀名得到打开方式
        /// </summary>
        /// <param name="_sExten"></param>
        /// <returns></returns>
        private string LoadOpenFileType(string _sExten)
        {
            try
            {
                string sOpenType = "";
                switch (_sExten.ToLower())
                {
                    case "xls":
                    case "xlsx":
                        sOpenType = "Excel.Sheet";
                        break;
                    case "doc":
                    case "docx":
                        sOpenType = "Word.Document";
                        break;
                    case "ppt":
                        sOpenType = "PowerPoint.Show";
                        break;
                    case "vsd":
                    case "vsdx":
                        sOpenType = "Visio.Drawing";
                        break;
                    default:
                        sOpenType = "Word.Document";
                        break;
                }
                return sOpenType;

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 第三步:初始化office控件,加载Excel
        /// </summary>
        /// <param name="_sFilePath">本地文档路径</param>
        private void InitOfficeControl(string _sFilePath)
        {
            try
            {
                if (m_axFramerControl == null)
                {
                    throw new ApplicationException("请先初始化office控件对象!");
                }

                //this.m_axFramerControl.SetMenuDisplay(48);
                //这个方法很特别,一个组合菜单控制方法,我还没有找到参数的规律,有兴趣的朋友可以研究一下
                string sExt = System.IO.Path.GetExtension(_sFilePath).Replace(".", "");
                //this.m_axFramerControl.CreateNew(this.LoadOpenFileType(sExt));//创建新的文件
                this.m_axFramerControl.Open(_sFilePath, false, this.LoadOpenFileType(sExt), "", "");//打开文件
                //隐藏标题
                this.m_axFramerControl.Titlebar = false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 关闭当前界面
        /// </summary>
        public void CloseFrom()
        {
            try
            {
                if (this.m_axFramerControl != null)
                {
                    this.m_axFramerControl.Close();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                CloseFrom();
            }
            catch (Exception)
            {
            }
        }
        #endregion


        #region 方法
        // 获得当前窗体
        Window GetActiveWindow(object Document)
        {
            if (Document == null)
            {
                return null;
            }

            Workbook workbook = null;
            Worksheet worksheet = null;
            try
            {
                //// 获取当前工作薄
                workbook = (Microsoft.Office.Interop.Excel.Workbook)Document;
                //// 获取当前工作页
                worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.ActiveSheet;
                Window window = null;

                if (worksheet != null)
                {
                    //// 获取当前活动窗口
                    window = worksheet.Application.ActiveWindow;
                }

                return window;
            }
            catch
            {
                return null;
            }
        }
        Range GetSelectionCell(object Document)
        {
            if (Document == null)
            {
                return null;
            }

            Workbook workbook = null;
            Worksheet worksheet = null;
            try
            {
                workbook = (Microsoft.Office.Interop.Excel.Workbook)Document;
                worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.ActiveSheet;
                Range range = null;

                if (worksheet != null)
                {
                    //// 获取所选区域的第一次选中的单元格
                    range = worksheet.Application.ActiveCell;
                }

                return range;
            }
            catch
            {
                return null;
            }

        }

        public System.Data.DataTable GetDataFromExcel(string filePath)

        {
            string connStr = "";


            string fileType = System.IO.Path.GetExtension(filePath);
            if (string.IsNullOrEmpty(fileType)) return null;
            if (fileType == ".xls")
                connStr = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + filePath + ";" + ";Extended Properties=\"Excel 8.0;HDR=NO;IMEX=1\"";
            else
                connStr = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + filePath + ";" + ";Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1\"";
            string sql_F = "Select * FROM [{0}]  ";
            OleDbConnection conn = null;
            OleDbDataAdapter da = null;
            System.Data.DataTable dataTable = new System.Data.DataTable();
            try
            {
                // 初始化连接,并打开                    
                conn = new OleDbConnection(connStr);
                conn.Open();
                da = new OleDbDataAdapter();
                da.SelectCommand = new OleDbCommand(String.Format(sql_F, "Sheet1$"), conn);
                da.Fill(dataTable);
            }
            catch (Exception ex)
            {


            }
            finally
            {                  // 关闭连接                    
                if (conn.State == ConnectionState.Open)
                {
                    conn.Close();
                    da.Dispose();
                    conn.Dispose();
                }
            }
            conn.Close();
            da.Dispose();
            conn.Dispose();
            return dataTable;
        }

        #region - 由数字转换为Excel中的列字母 -

        public int ToIndex(string columnName)
        {
            if (!Regex.IsMatch(columnName.ToUpper(), @"[A-Z]+")) { throw new Exception("invalid parameter"); }

            int index = 0;
            char[] chars = columnName.ToUpper().ToCharArray();
            for (int i = 0; i < chars.Length; i++)
            {
                index += ((int)chars[i] - (int)'A' + 1) * (int)Math.Pow(26, chars.Length - i - 1);
            }
            return index - 1;
        }


        public string ToName(int index)
        {
            if (index < 0) { throw new Exception("invalid parameter"); }

            List<string> chars = new List<string>();
            do
            {
                if (chars.Count > 0) index--;
                chars.Insert(0, ((char)(index % 26 + (int)'A')).ToString());
                index = (int)((index - index % 26) / 26);
            } while (index > 0);

            return String.Join(string.Empty, chars.ToArray());
        }
        #endregion


        /// <summary>  
        /// 反一个M行N列的二维数组转换为DataTable  
        /// </summary>  
        /// <param name="ColumnNames">一维数组,代表列名,不能有重复值</param>  
        /// <param name="Arrays">M行N列的二维数组</param>  
        /// <returns>返回DataTable</returns>  
        /// <remarks>柳永法 http://www.yongfa365.com/ </remarks>  
        public static System.Data.DataTable ConvertToDataTable(string[] ColumnNames, string[,] Arrays)
        {
            System.Data.DataTable dt = new System.Data.DataTable();

            foreach (string ColumnName in ColumnNames)
            {
                dt.Columns.Add(ColumnName, typeof(string));
            }

            for (int i1 = 0; i1 < Arrays.GetLength(0); i1++)
            {
                DataRow dr = dt.NewRow();
                bool isData = false;
                for (int i = 0; i < ColumnNames.Length; i++)
                {
                    if (Arrays[i1, i] != null)
                    {
                        isData = true;
                        dr[i] = Arrays[i1, i].ToString();
                    }
                }
                if (isData)
                    dt.Rows.Add(dr);
            }

            return dt;

        }

        private string GetNameFromDt(System.Data.DataTable dt)
        {
            string str = "";
            foreach (DataRow dr in dt.Rows)
            {
                str += dr["Name"].ToString() + ",";
            }
            return str.TrimEnd(',');
        }
        #endregion


    }
}

 

posted @ 2018-09-14 15:51  辛勤的蚂蚁  阅读(18876)  评论(5编辑  收藏  举报