您好,登錄后才能下訂單哦!
怎么在DataGridView中實(shí)現(xiàn)右鍵菜單自定義顯示及隱藏列功能?針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。
1、新建一個(gè)自定義控件,命名為:PopupMenuControl。
2、在PopupMenuControl.Designet文件中的InitializeComponent()方法下面,注冊(cè)以下事件:
this.Paint += new System.Windows.Forms.PaintEventHandler(this.PopupMenuControl_Paint); this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PopupMenuControl_MouseDown); this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PopupMenuControl_MouseMove);
3、PopupMenuControl的代碼:
public partial class PopupMenuControl : UserControl { public delegate void CheckedChanged(int hitIndex, bool isChecked); //勾選改變委托 public event CheckedChanged CheckedChangedEvent; //勾選改變事件 PopupMenuHelper popupMenuHelper = null; //菜單幫助類,主要負(fù)責(zé)菜單繪制。 public PopupMenuControl() { InitializeComponent(); } public void Initialize(DataGridView dgvTarget) { //菜單幫助類實(shí)例化 popupMenuHelper = new PopupMenuHelper(); //將列標(biāo)題添加到items foreach (DataGridViewColumn column in dgvTarget.Columns) { popupMenuHelper.AddItem(column.HeaderText, column.Visible); } //菜單繪制 popupMenuHelper.Prepare(CreateGraphics()); Width = popupMenuHelper.Width; Height = popupMenuHelper.Height; } /// <summary> /// 繪制 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void PopupMenuControl_Paint(object sender, PaintEventArgs e) { popupMenuHelper.Draw(e.Graphics); } /// <summary> /// 鼠標(biāo)移過 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void PopupMenuControl_MouseMove(object sender, MouseEventArgs e) { if (popupMenuHelper.IsMouseMove(e.X, e.Y)) { popupMenuHelper.Draw(CreateGraphics()); } } /// <summary> /// 鼠標(biāo)按下 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void PopupMenuControl_MouseDown(object sender, MouseEventArgs e) { if (popupMenuHelper.IsMouseDown(e.X, e.Y)) { int hitIndex = popupMenuHelper.HitIndex; if (hitIndex != -1) { bool isChecked = popupMenuHelper.IsCheckedChange(hitIndex, CreateGraphics()); OnCheckedChanged(hitIndex, isChecked); } } } /// <summary> /// 勾選改變 /// </summary> /// <param name="iIndex"></param> /// <param name="bChecked"></param> public virtual void OnCheckedChanged(int hitIndex, bool isChecked) { CheckedChangedEvent?.Invoke(hitIndex, isChecked); } }
4、這上面涉及到一個(gè)PopupMenuHelper的幫助類,此幫助類主要是為PopupMenuControl控件實(shí)現(xiàn)菜單繪制的功能,其代碼如下:
class PopupMenuHelper { //變量 private PopupMenuItem hotItem = null; //當(dāng)前Item private List<PopupMenuItem> items = new List<PopupMenuItem>(); //Item集合 private Bitmap bitmap; //位圖 private Graphics graphics; //圖像 private static readonly int BasicConst = 24; //Item:高度、Image寬度 private static readonly int BasicGap = 3; //四周間距 private static readonly int BasicRows = 3; //最大行數(shù) private static readonly int BasicSide = 10; //Item:CheckBox邊長(zhǎng)(建議用偶數(shù)) private int totality = 1; //分割總數(shù) private int[] eachWidth = null; //各個(gè)寬度 //屬性 public int Width { get { return bitmap.Width; } } //寬度 public int Height { get { return bitmap.Height; } } //高度 //PopupMenuItem類 private class PopupMenuItem { //屬性 public string ItemText { get; set; } //Item文本 public bool IsChecked { get; set; } //勾選狀態(tài) //構(gòu)造函數(shù) public PopupMenuItem(string itemText) : this(itemText, false) { } public PopupMenuItem(string itemText, bool isChecked) { ItemText = itemText; IsChecked = isChecked; } } //無參構(gòu)造函數(shù) public PopupMenuHelper() { } /// <summary> /// 被點(diǎn)擊Item的Index /// </summary> public int HitIndex { get { return items.IndexOf(hotItem); } } /// <summary> /// 勾選改變狀態(tài) /// </summary> /// <param name="hitIndex">被點(diǎn)擊Item的Index</param> /// <param name="g">圖像</param> /// <returns></returns> public bool IsCheckedChange(int hitIndex, Graphics g) { items[hitIndex].IsChecked = !items[hitIndex].IsChecked; Draw(g); return items[hitIndex].IsChecked; } /// <summary> /// 添加Item /// </summary> /// <param name="itemText">Item文本</param> /// <param name="isChecked">Item勾選狀態(tài)</param> public void AddItem(string itemText, bool isChecked) { items.Add(new PopupMenuItem(itemText, isChecked)); } /// <summary> /// 繪制菜單準(zhǔn)備 /// </summary> /// <param name="g">圖像</param> public void Prepare(Graphics g) { //獲取菜單的寬度及高度 totality = (int)Math.Ceiling((double)items.Count / BasicRows); eachWidth = new int[totality]; int totalWidth = 0, totalHeight = 0; double maxTextWidth = 0; if (totality == 1) { totalHeight = items.Count * BasicConst + 2 * BasicGap; foreach (PopupMenuItem item in items) { //SizeF:存儲(chǔ)有序浮點(diǎn)數(shù)對(duì),通常為矩形的寬度和高度。 SizeF sizeF = g.MeasureString(item.ItemText, SystemInformation.MenuFont); maxTextWidth = Math.Max(maxTextWidth, sizeF.Width); } totalWidth = (int)Math.Ceiling((double)maxTextWidth) + BasicConst + 2 * BasicGap; eachWidth[0] = (int)Math.Ceiling((double)maxTextWidth) + BasicConst; } else { totalHeight = BasicRows * BasicConst + 2 * BasicGap; int rows = 0, cols = 1; foreach (PopupMenuItem item in items) { rows++; //SizeF:存儲(chǔ)有序浮點(diǎn)數(shù)對(duì),通常為矩形的寬度和高度。 SizeF sizeF = g.MeasureString(item.ItemText, SystemInformation.MenuFont); maxTextWidth = Math.Max(maxTextWidth, sizeF.Width); if (cols < totality) { //1..[totality-1]列 if (rows == BasicRows) { totalWidth += (int)Math.Ceiling((double)maxTextWidth) + BasicConst; eachWidth[cols - 1] = (int)Math.Ceiling((double)maxTextWidth) + BasicConst; maxTextWidth = 0; cols++; rows = 0; } } else { //totality列 if ((cols - 1) * BasicRows + rows == items.Count) { totalWidth += (int)Math.Ceiling((double)maxTextWidth) + BasicConst + 2 * BasicGap; eachWidth[cols - 1] = (int)Math.Ceiling((double)maxTextWidth) + BasicConst; } } } } //圖像初始化 bitmap = new Bitmap(totalWidth, totalHeight); graphics = Graphics.FromImage(bitmap); } /// <summary> /// 繪制菜單 /// </summary> /// <param name="g"></param> public void Draw(Graphics g) { Rectangle area = new Rectangle(0, 0, bitmap.Width, bitmap.Height); graphics.Clear(SystemColors.Menu); DrawBackground(graphics, area); DrawItems(graphics); g.DrawImage(bitmap, area, area, GraphicsUnit.Pixel); } /// <summary> /// 繪制菜單背景 /// </summary> /// <param name="g"></param> /// <param name="area"></param> private void DrawBackground(Graphics g, Rectangle area) { //描邊 using (Pen borderPen = new Pen(Color.FromArgb(112, 112, 112))) g.DrawRectangle(borderPen, area); //Image及Text int left = BasicGap, top = BasicGap; if (totality == 1) { Rectangle imageArea = new Rectangle(left, top, BasicConst, items.Count * BasicConst); using (Brush backBrush = new SolidBrush(Color.FromArgb(240, 240, 240))) g.FillRectangle(backBrush, imageArea); Rectangle textArea = new Rectangle(left + BasicConst, top, eachWidth[0], items.Count * BasicConst); using (Brush backBrush = new SolidBrush(Color.FromArgb(255, 255, 255))) g.FillRectangle(backBrush, textArea); } else { for (int i = 0; i < totality; i++) { Rectangle imageArea = new Rectangle(left, top, BasicConst, BasicRows * BasicConst); using (Brush backBrush = new SolidBrush(Color.FromArgb(240, 240, 240))) g.FillRectangle(backBrush, imageArea); Rectangle textArea = new Rectangle(left + BasicConst, top, eachWidth[i], BasicRows * BasicConst); using (Brush backBrush = new SolidBrush(Color.FromArgb(255, 255, 255))) g.FillRectangle(backBrush, textArea); left += eachWidth[i]; } } } /// <summary> /// 繪制所有菜單Item /// </summary> /// <param name="g">圖像</param> private void DrawItems(Graphics g) { int left = BasicGap, top = BasicGap; int rows = 0, cols = 1; foreach (PopupMenuItem item in items) { if (totality == 1) { DrawSingleItem(g, left, ref top, eachWidth[0], item, item == hotItem); } else { rows++; DrawSingleItem(g, left, ref top, eachWidth[cols - 1], item, item == hotItem); //1..[totality-1]列 if (rows % BasicRows == 0) { left += eachWidth[cols - 1]; top = BasicGap; cols++; rows = 0; } } } } /// <summary> /// 繪制單個(gè)菜單Item /// </summary> /// <param name="g">圖像</param> /// <param name="top">圖像Top</param> /// <param name="item">菜單Item</param> /// <param name="isHotItem">是否為當(dāng)前菜單Item</param> private void DrawSingleItem(Graphics g, int left, ref int top,int width, PopupMenuItem item, bool isHotItem) { //Item區(qū)域 Rectangle drawRect = new Rectangle(left, top, width, BasicConst); top += BasicConst; //Text區(qū)域 Rectangle itemTextArea = new Rectangle ( drawRect.Left + BasicConst, drawRect.Top, drawRect.Width - BasicConst, drawRect.Height ); //背景色及描邊色 if (isHotItem) { //HotItem Rectangle hotItemArea = new Rectangle(drawRect.Left, drawRect.Top, drawRect.Width, drawRect.Height); using (SolidBrush backBrush = new SolidBrush(Color.FromArgb(214, 235, 255))) g.FillRectangle(backBrush, hotItemArea); using (Pen borderPen = new Pen(Color.FromArgb(51, 153, 255))) g.DrawRectangle(borderPen, hotItemArea); } //Text處理 StringFormat itemTextFormat = new StringFormat(); //NoClip:允許顯示字形符號(hào)的伸出部分和延伸到矩形外的未換行文本。 //NoWrap:在矩形內(nèi)設(shè)置格式時(shí),禁用自動(dòng)換行功能。 itemTextFormat.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap; //Near:指定文本靠近布局對(duì)齊。 itemTextFormat.Alignment = StringAlignment.Near; //Center:指定文本在布局矩形中居中對(duì)齊(呃,感覺不是很垂直居中,偏上了一些)。 itemTextFormat.LineAlignment = StringAlignment.Center; //Show:顯示熱鍵前綴。 itemTextFormat.HotkeyPrefix = HotkeyPrefix.Show; SolidBrush textBrush = new SolidBrush(SystemColors.MenuText); g.DrawString(item.ItemText, SystemInformation.MenuFont, textBrush, itemTextArea, itemTextFormat); //Checkbox處理 if (item.IsChecked) { int checkBoxGap = (int)((drawRect.Height - BasicSide) / 2); int checkBoxLeft = drawRect.Left + checkBoxGap; int checkBoxTop = drawRect.Top + checkBoxGap; //將checkBoxArea的Top減1,與文本的對(duì)齊效果稍微好一些。 Rectangle checkBoxArea = new Rectangle(checkBoxLeft, checkBoxTop - 1, BasicSide, BasicSide); using (Brush checkBoxBrush = new SolidBrush(Color.FromArgb(214, 235, 255))) g.FillRectangle(checkBoxBrush, checkBoxArea); using (Pen checkBoxPen = new Pen(Color.FromArgb(51, 153, 255))) g.DrawRectangle(checkBoxPen, checkBoxArea); using (Pen checkBoxTick = new Pen(Color.FromArgb(51, 153, 255))) { g.DrawLine(checkBoxTick, new Point(checkBoxLeft, checkBoxTop - 1 + (int)(BasicSide / 2)), new Point(checkBoxLeft + (int)(BasicSide / 2), checkBoxTop - 1 + BasicSide)); g.DrawLine(checkBoxTick, new Point(checkBoxLeft + (int)(BasicSide / 2), checkBoxTop - 1 + BasicSide), new Point(checkBoxLeft + BasicSide + BasicGap, checkBoxTop - 1 - BasicGap)); } } } /// <summary> /// 點(diǎn)擊測(cè)試 /// </summary> /// <param name="X">X坐標(biāo)</param> /// <param name="Y">Y坐標(biāo)</param> /// <returns></returns> private PopupMenuItem HitTest(int X, int Y) { if (X < 0 || X > Width || Y < 0 || Y > Height) { return null; } int left = BasicGap, top = BasicGap; int rows = 0, cols = 1; foreach (PopupMenuItem item in items) { if (totality == 1) { rows++; if (X > left && X < left + eachWidth[0] && Y > top + (rows - 1) * BasicConst && Y < top + rows * BasicConst) { return item; } } else { rows++; if (X > left && X < left + eachWidth[cols - 1] && Y > top + (rows - 1) * BasicConst && Y < top + rows * BasicConst) { return item; } //1..[totality-1]列 if (rows % BasicRows == 0) { left += eachWidth[cols - 1]; top = BasicGap; cols++; rows = 0; } } } return null; } /// <summary> /// 是否是鼠標(biāo)移過 /// </summary> /// <param name="X">X坐標(biāo)</param> /// <param name="Y">Y坐標(biāo)</param> /// <returns></returns> public bool IsMouseMove(int X, int Y) { PopupMenuItem popupMenuItem = HitTest(X, Y); if (popupMenuItem != hotItem) { hotItem = popupMenuItem; return true; } else { return false; } } /// <summary> /// 是否是鼠標(biāo)按下 /// </summary> /// <param name="X">X坐標(biāo)</param> /// <param name="Y">Y坐標(biāo)</param> /// <returns></returns> public bool IsMouseDown(int X, int Y) { PopupMenuItem popupMenuItem = HitTest(X, Y); return popupMenuItem != null; } }
這個(gè)類實(shí)現(xiàn)了多菜單頁面的功能:即如果DataGridView字段非常的多,可通過產(chǎn)生多列菜單來顯示,程序是通過BasicRows變量來控制。
5、新建一個(gè)DataGridViewColumnSelector類,此類的功能主要是銜接DataGridView與PopupMenuControl,其代碼如下:
/// <summary> /// DataGridView右鍵菜單自定義顯示及隱藏列 /// </summary> class DataGridViewColumnSelector { private DataGridView dgvTarget = null; //待處理的DataGridView對(duì)象 private ToolStripDropDown dropDown; //用于加載PopupMenu控件 PopupMenuControl popupMenuControl = new PopupMenuControl(); //PopupMenu控件 //無參構(gòu)造函數(shù) public DataGridViewColumnSelector() { //注冊(cè)PopupMenu控件事件 popupMenuControl.CheckedChangedEvent += new PopupMenuControl.CheckedChanged(OnCheckedChanged); //使用容器承載PopupMenu控件(相當(dāng)于容器類型的ToolStripItem) ToolStripControlHost controlHost = new ToolStripControlHost(popupMenuControl); controlHost.Padding = Padding.Empty; controlHost.Margin = Padding.Empty; controlHost.AutoSize = false; //加載PopupMenu控件 dropDown = new ToolStripDropDown(); dropDown.Padding = Padding.Empty; dropDown.AutoClose = true; dropDown.Items.Add(controlHost); } //有參構(gòu)造函數(shù) public DataGridViewColumnSelector(DataGridView dataGridView) : this() { DataGridView = dataGridView; } //DataGridView屬性 public DataGridView DataGridView { get { return dgvTarget; } set { //去除單元格點(diǎn)擊事件 if (dgvTarget != null) { dgvTarget.CellMouseClick -= new DataGridViewCellMouseEventHandler(DataGridView_CellMouseClick); } dgvTarget = value; //注冊(cè)單元格點(diǎn)擊事件 if (dgvTarget != null) { dgvTarget.CellMouseClick += new DataGridViewCellMouseEventHandler(DataGridView_CellMouseClick); } } } /// <summary> /// 右鍵點(diǎn)擊標(biāo)題欄彈出菜單 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) { if (e.Button == MouseButtons.Right && e.RowIndex == -1) { popupMenuControl.Initialize(dgvTarget); //將菜單顯示在光標(biāo)位置 dropDown.Show(Cursor.Position); } } /// <summary> /// 勾選事件執(zhí)行方法 /// </summary> /// <param name="hitIndex"></param> /// <param name="isCheck"></param> private void OnCheckedChanged(int hitIndex, bool isChecked) { dgvTarget.Columns[hitIndex].Visible = isChecked; } }
6、以上這些,已經(jīng)實(shí)現(xiàn)了全部的功能。下面開始建一個(gè)WinForm程序來測(cè)試結(jié)果,為方便測(cè)試將DataGridView的數(shù)據(jù)源由xml文件讀取。
從SQL Server數(shù)據(jù)庫隨便找張數(shù)據(jù)表生成XML,文件保存為Test.xml。(請(qǐng)將Test.xml文件拷貝到Debug文件夾下面)
SELECT TOP 10 MO_NO,MRP_NO,QTY,BIL_NO FROM MF_MO WHERE MO_DD='2019-11-07' ORDER BY MO_NO FOR XML PATH ('Category'),TYPE,ROOT('DocumentElement')
7、新建一個(gè)WinForm程序,命名為Main,并拖入一個(gè)DataGridView控件,Main_Load方法如下:
private void Main_Load(object sender, EventArgs e) { try { //xml文件路徑 string path = @"Test.xml"; //讀取文件 DataSet ds = new DataSet(); if (File.Exists(path)) { ds.ReadXml(path); } dataGridView1.DataSource = ds.Tables.Count > 0 ? ds.Tables[0] : null; //加工dataGridView1 #region 加列標(biāo)題測(cè)試 dataGridView1.Columns[0].HeaderText = "制令單號(hào)"; dataGridView1.Columns[1].HeaderText = "成品編號(hào)"; dataGridView1.Columns[2].HeaderText = "生產(chǎn)數(shù)量"; dataGridView1.Columns[3].HeaderText = "來源單號(hào)"; #endregion DataGridViewColumnSelector columnSelector = new DataGridViewColumnSelector(dataGridView1); } catch (Exception ex) { MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } }
8、執(zhí)行程序,在任意DataGridView標(biāo)題欄右擊,即可彈出菜單:
關(guān)于怎么在DataGridView中實(shí)現(xiàn)右鍵菜單自定義顯示及隱藏列功能問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。