星期四, 7月 21, 2022

[C#] DataGridView - Mouse Click

公司系統慣例是點選 DataGridView 非 DisplayedRow 區域新增空白資料,在 VFP GridView Mouse Click 相關事件,在 DisplayedRow 內是不會觸發,非 DisplayedRow 才會,而 C# WinForm 則是都會。

該差異導致移轉新系統後,使用者操作上不順暢,常常莫名就會新增資料至 DataGridView 內去,需要手動去刪除空白資料,就是會要求儲存時自動把空白資料刪除,特地去找出解法,讓 C# Mouse Click 事件只會在非 DisplayedRow 上觸發,減少這類無意義 feedback

DisplayedRow 名詞介紹

是從 C# DataGridView 看來,直接看圖較直白
  • 綠框為 DisplayRow
  • 藍框在官方文件上查不到專有名稱,就稱呼非 DisplayedRow 區域或空白區吧
[C#] DataGridView - Mouse Click-1


DataGridView 上顯示的資料筆數,透過 includePartialRow 參數來決定是否抓取顯示不完整的 Row,以下圖為例,false 是抓到兩筆,true 則為三筆

[C#] DataGridView - Mouse Click-2


抓取 DataGridView 上顯示第一筆 Row 的 RowInde,以下圖為例,會抓到編號 5 資料的 RowIndex

[C#] DataGridView - Mouse Click-3


自訂 DataGridView 

該筆記是在 MouseDown 事件並建立 InsertNewDataRow Event 來進行改寫,實務上就根據需求,看要在哪個 Mouse Click 事件內處理,也可以把整個 Mouse Click 事件都覆寫掉,那也就不需要特別去建立事件來觸發

該寫法個重點
  • 點擊在 ColumnHeader 時不觸發
  • 點擊在 RowHeader 時不觸發
  • 點擊在非 DisplayedRow 區域時觸發
  • ScrollBar 出現時,ScrollBar 必須在最下方時觸發
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace UCDataGridViewMouseDown
{
    public class UCDataGridView : DataGridView
    {
        [Description("點擊 DataGridView 非 DisplayedRow 區域時觸發")]
        public event EventHandler InsertNewDataRow;

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            int displayRowCount = DisplayedRowCount(false);
            int rowHeightIncludeHeaderHeight = ColumnHeadersHeight + (RowTemplate.Height * displayRowCount);
            
            bool isClickInRowHeader = RowHeadersWidth > e.X;            
            bool isClickInColumnHeader = ColumnHeadersHeight >= e.Y;
            bool isClickInNonDisplayedRow = rowHeightIncludeHeaderHeight < e.Y;

            if (isClickInRowHeader ||
                isClickInColumnHeader)
                return;

            VScrollBar vScrollBar = Controls.OfType<VScrollBar>().First();

            int rowIndexMax = RowCount - 1;
            // DataGridView 畫面上第一筆資料的 RowIndex 加上 畫面上資料筆數
            int indexStat = FirstDisplayedScrollingRowIndex + displayRowCount;
            bool isScrolBottom = indexStat > rowIndexMax;

            if (isClickInNonDisplayedRow && (
                    RowCount == 0 ||
                    vScrollBar.Visible == false ||
                    (vScrollBar.Visible == true && isScrolBottom)))
                    InsertNewDataRow?.Invoke(this, e);
        }
    }
}
把自訂控件拉進 Form 內使用
using System;
using System.Data;
using System.Windows.Forms;

namespace UCDataGridViewMouseDown
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.InsertNewDataRow += DataGridView1_InsertNewDataRow;

            DataTable dt = new DataTable();
            dt.Columns.Add("ID", typeof(int));
            dt.Columns.Add("Name", typeof(string));
            dt.Rows.Add(1, "姓名一");
            dt.Rows.Add(2, "姓名二");
            dt.Rows.Add(3, "姓名三");
            dt.Rows.Add(4, "姓名四");
            dt.Rows.Add(5, "姓名五");
            dt.Rows.Add(6, "姓名六");
            dataGridView1.DataSource = dt;
        }

        private void DataGridView1_InsertNewDataRow(object sender, EventArgs e)
        {
            MessageBox.Show(nameof(UCDataGridView.InsertNewDataRow));
        }
    }
}
  • 參考資料
  • 網路討論 12

沒有留言:

張貼留言