前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Excel催化剂开源第13波-VSTO开发之DataGridView控件几个小坑

Excel催化剂开源第13波-VSTO开发之DataGridView控件几个小坑

作者头像
Excel催化剂
发布2021-08-19 15:01:13
1.1K0
发布2021-08-19 15:01:13
举报
文章被收录于专栏:Excel催化剂

Excel催化剂内部大量使用了DataGridView,这其中有一些小坑,花了力气才解决的,在此给广大开发者作简单分享。

为何要使用DataGridView而不是其他控件如ListBox、ListView、ComboBox之类的?因为大量的数据,特别是配置信息,都是以数据库表结构的一维表存储最为合理,一般一个配置是多列内容来定义其多样的属性。

用DataGridView最有优势之处在于,可以直接让DataTable直接绑定即可,同时带有丰富的事件可与用户交互,并且保留有用户常用的排序功能,筛选功能也容易实现,用Dataview来绑定数据源即可。

使用DataGridView的一些小坑

DataGridView内复选框状态改变激活事件

在Excel催化剂的【工作表导航】功能中,有用到DataGridView存储工作表信息,需要和用户交互的是用户点击复选框,可以对工作表的显示隐藏状态进行改变。

image.png

若直接在Checkbox列上写CellValueChanged事件,会发现不起作用的。当然这一步也不可少。

代码语言:javascript
复制
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (Common.ExcelApp.ActiveWorkbook.ProtectStructure == false)
            {
                if (e.RowIndex != -1 && !dataGridView1.Rows[e.RowIndex].IsNewRow)
                {
                    //复选框列
                    if (e.ColumnIndex == 1)
                    {
                        string worksheetName = this.dataGridView1[0, e.RowIndex].Value.ToString();
                        Excel._Worksheet wht = Common.ExcelApp.ActiveWorkbook.Worksheets[worksheetName];
                        try
                        {
                            if ((bool)this.dataGridView1[e.ColumnIndex, e.RowIndex].Value == true)
                            {
                                wht.Visible = Excel.XlSheetVisibility.xlSheetVisible;
                            }
                            else
                            {
                                wht.Visible = Excel.XlSheetVisibility.xlSheetHidden;
                            }
                        }
                        catch (Exception)
                        {
                            MessageBox.Show($"操作有误,错误原因为:\r\n工作薄至少需要一个工作表为可见的!");
                            this.dataGridView1[e.ColumnIndex, e.RowIndex].Value = true;
                        }

                    }

                }

            }
            else
            {
                MessageBox.Show("工作薄受保护状态不可操作工作表显示/隐藏操作!");
                this.dataGridView1.CellValueChanged -= dataGridView1_CellValueChanged;
                this.dataGridView1[e.ColumnIndex, e.RowIndex].Value = true;
                this.dataGridView1.CellValueChanged += dataGridView1_CellValueChanged;
            }

        }

需要加上这个事件才可生效,具体原理可自行百度

代码语言:javascript
复制
        /// <summary>
        /// 这个为了让复选框可以单击时产生变化而用的。网上抄的。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if (dataGridView1.IsCurrentCellDirty)
            {
                dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }
        }
DataGridView的行手工排序问题

DataGridView原生功能没有实现通过按住某行拖动的方式实现不同行之间的排序问题。在百度上搜索了一些代码实现了此功能。

在Excel催化剂上的使用场景为,对工作表的手工排序操作。

手工排序效果

首先要打开这个AllowDrop属性

AllowDrop打开

具体代码段

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
namespace Excel催化剂
{
    public partial class formSheetSort : Form
    {
        public formSheetSort()
        {
            InitializeComponent();
            this.Icon = Properties.Resources.Excel催化剂logo32;
        }

        private void formSheetSort_Load(object sender, EventArgs e)
        {
            ReloadSheetName();
        }





        private void btnEnsureOrderSheetName_Click(object sender, EventArgs e)
        {
            try
            {
                Common.ExcelApp.ScreenUpdating = false;
                int shtCount = Common.ExcelApp.ActiveWorkbook.Worksheets.Count;
                foreach (DataGridViewRow row in this.dgv.Rows)
                {
                    Excel.Worksheet sht = Common.ExcelApp.ActiveWorkbook.Worksheets[row.Cells[0].Value];
                    sht.Move(After: Common.ExcelApp.ActiveWorkbook.Worksheets[shtCount]);
                }
            }
            catch (Exception ex )
            {

                MessageBox.Show("操作出错,出错原因为" + ex.Message);
            }
            finally
            {
                Common.ExcelApp.ScreenUpdating = true;
            }

        }

        private void ReloadSheetName()
        {
            foreach (Excel.Worksheet item in Common.ExcelApp.ActiveWorkbook.Worksheets)
            {
                DataGridViewRow row = new DataGridViewRow();
                int sheetNameIndex = this.SheetName.Index;

                int rowIndex = this.dgv.Rows.Add();
                this.dgv.Rows[rowIndex].Cells[sheetNameIndex].Value = item.Name;

            }

        }

        private int selectionIdx = 0;
        private void dgv_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.RowIndex >= 0)
                selectionIdx = e.RowIndex;
        }

        private void dgv_CellMouseMove(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridView dgv = sender as DataGridView;
            if ((e.Clicks < 2) && (e.Button == MouseButtons.Left))
            {
                if ((e.ColumnIndex == -1) && (e.RowIndex > -1))
                    dgv.DoDragDrop(dgv.Rows[e.RowIndex], DragDropEffects.Move);
            }
        }

        private void dgv_DragDrop(object sender, DragEventArgs e)
        {
            DataGridView dgv = sender as DataGridView;
            int idx = GetRowFromPoint(e.X, e.Y);
            if (idx < 0) return;

            if (e.Data.GetDataPresent(typeof(DataGridViewRow)))
            {
                DataGridViewRow row = (DataGridViewRow)e.Data.GetData(typeof(DataGridViewRow));

                int rowIndex = row.Index;
                if (idx < rowIndex)
                {
                    dgv.Rows.Remove(row);
                    selectionIdx = idx;
                    dgv.Rows.Insert(idx, row);
                }
                else
                {
                    dgv.Rows.Remove(row);
                    selectionIdx = idx - 1;
                    dgv.Rows.Insert(idx - 1, row);

                }

            }
        }

        private void dgv_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        {
            DataGridView dgv = sender as DataGridView;
            if (selectionIdx > -1 && dgv.Rows.Count > 0)
            {
                dgv.Rows[selectionIdx].Selected = true;
                dgv.CurrentCell = dgv.Rows[selectionIdx].Cells[0];
            }
        }


        private void dgv_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }

        private int GetRowFromPoint(int x, int y)
        {

            for (int i = 0; i < this.dgv.RowCount; i++)
            {
                Rectangle rec = this.dgv.GetRowDisplayRectangle(i, false);

                if (this.dgv.RectangleToScreen(rec).Contains(x, y))
                    return i;
            }

            return -1;
        }
    }
}

结语

在.Net下写VSTO插件,没有理由再用VBA那些落后的控件,DataGridView、Ado.Net这些在.Net环境里的数据控件和数据存储技术是首选,代码书写更流畅,开发效率更高,用户体验也是超棒。

此篇给大家扫清几个小坑,让大家开发过程中,更顺畅,尽情地在业务逻辑代码上发挥,少关注底层这些莫名的坑坑洼洼。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Excel催化剂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用DataGridView的一些小坑
    • DataGridView内复选框状态改变激活事件
      • DataGridView的行手工排序问题
      • 结语
      相关产品与服务
      数据保险箱
      数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档