zoukankan      html  css  js  c++  java
  • C# DataGridView右键菜单自定义显示及隐藏列(转载)

    原文地址:https://www.cnblogs.com/atomy/archive/2019/11/12/11812458.html

    在这个基础上改了下,我加了个全选和按名称的没有按索引

       1、新建一个自定义控件,命名为:PopupMenuControl。

        2、在PopupMenuControl.Designet文件中的InitializeComponent()方法下面,注册以下事件:

        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;                    //勾选改变事件
            public delegate void CheckedChanged(string itemText, bool isChecked);  //勾选改变委托
            public event CheckedChanged CheckedChangedEvent;                    //勾选改变事件
            PopupMenuHelper popupMenuHelper = null;
    
            public PopupMenuControl()
            {
                InitializeComponent();
            }
    
            private void PopupMenuControl_Load(object sender, EventArgs e)
            {
    
            }
    
            //菜单帮助类,主要负责菜单绘制。
            public void Initialize(DataGridView dgvTarget)
            {
                //菜单帮助类实例化
                popupMenuHelper = new PopupMenuHelper();
                bool isQuan = true;
                popupMenuHelper.AddItem("全选", isQuan);
                //将列标题添加到items
                foreach (DataGridViewColumn column in dgvTarget.Columns)
                {
                    if (!column.Visible)
                        isQuan = false;
                    popupMenuHelper.AddItem(column.HeaderText, column.Visible);
                }
                popupMenuHelper.UpdateItem(isQuan);
    
                //菜单绘制
                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>
            /// 鼠标移过
            /// </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>
            /// 鼠标按下
            /// </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)
                    string itemText = popupMenuHelper.ItemText;
                    if (!string.IsNullOrEmpty(itemText))
                    {
                        bool isChecked = popupMenuHelper.IsCheckedChange(itemText, CreateGraphics());
                        OnCheckedChanged(itemText, isChecked);
                    }
                }
            }
    
            ///// <summary>
            ///// 勾选改变
            ///// </summary>
            ///// <param name="iIndex"></param>
            ///// <param name="bChecked"></param>
            //public virtual void OnCheckedChanged(int hitIndex, bool isChecked)
            //{
            //    CheckedChangedEvent?.Invoke(hitIndex, isChecked);
            //}
    
            /// <summary>
            /// 勾选改变
            /// </summary>
            /// <param name="iIndex"></param>
            /// <param name="bChecked"></param>
            public virtual void OnCheckedChanged(string itemText, bool isChecked)
            {
                CheckedChangedEvent?.Invoke(itemText, isChecked);
            }
        }
    
        class PopupMenuHelper
        {
            //变量
            private PopupMenuItem hotItem = null;                           //当前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 = 10;                      //最大行数
            private static readonly int BasicSide = 10;                     //Item:CheckBox边长(建议用偶数)
            private int totality = 1;                                       //分割总数
            private int[] eachWidth = null;                                 //各个宽度
    
            //属性
            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; }                         //勾选状态
    
                //构造函数
                public PopupMenuItem(string itemText) : this(itemText, false)
                {
                }
                public PopupMenuItem(string itemText, bool isChecked)
                {
                    ItemText = itemText;
                    IsChecked = isChecked;
                }
            }
    
            //无参构造函数
            public PopupMenuHelper()
            {
            }
    
            /// <summary>
            /// 被点击Item的Index
            /// </summary>
            public int HitIndex
            {
                get
                {
                    return items.IndexOf(hotItem);
                }
            }
    
            /// <summary>
            /// 被点击Item的名称
            /// </summary>
            public string ItemText
            {
                get
                {
                    return hotItem.ItemText;
                }
            }
    
            /// <summary>
            /// 勾选改变状态
            /// </summary>
            /// <param name="hitIndex">被点击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>
            /// 勾选改变状态
            /// </summary>
            /// <param name="hitIndex">被点击Item的Index</param>
            /// <param name="g">图像</param>
            /// <returns></returns>
            public bool IsCheckedChange(string ItemText, Graphics g)
            {
                items.Where(it => it.ItemText == ItemText).FirstOrDefault().IsChecked = !items.Where(it => it.ItemText == ItemText).FirstOrDefault().IsChecked;
                bool isChecked = items.Where(it => it.ItemText == ItemText).FirstOrDefault().IsChecked;
                if (ItemText == "全选")
                {
                    QuanItem(isChecked, g);
                }
                else
                {
                    bool isquan = false;
                    if (items.Where(it => it.IsChecked == false && it.ItemText != "全选").Count() <= 0)
                    {
                        isquan = true;
                    }
                    UpdateItem(isquan);
                    Draw(g);
                }
                Draw(g);
                return isChecked;
            }
    
            /// <summary>
            /// 添加Item
            /// </summary>
            /// <param name="itemText">Item文本</param>
            /// <param name="isChecked">Item勾选状态</param>
            public void AddItem(string itemText, bool isChecked)
            {
                items.Add(new PopupMenuItem(itemText, isChecked));
            }
    
            /// <summary>
            /// 修改全选的状态
            /// </summary>
            public void UpdateItem(bool isChecked)
            {
                var data = items.Where(it => it.ItemText == "全选").FirstOrDefault();
                if (data != null)
                {
                    data.IsChecked = isChecked;
                }
            }
    
            /// <summary>
            /// 修改全选的状态
            /// </summary>
            public void QuanItem(bool isChecked, Graphics g)
            {
                items.ForEach(it => it.IsChecked = isChecked);
                Draw(g);
            }
    
            /// <summary>
            /// 绘制菜单准备
            /// </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:存储有序浮点数对,通常为矩形的宽度和高度。
                        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:存储有序浮点数对,通常为矩形的宽度和高度。
                        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>
            /// 绘制单个菜单Item
            /// </summary>
            /// <param name="g">图像</param>
            /// <param name="top">图像Top</param>
            /// <param name="item">菜单Item</param>
            /// <param name="isHotItem">是否为当前菜单Item</param>
            private void DrawSingleItem(Graphics g, int left, ref int top, int width, PopupMenuItem item, bool isHotItem)
            {
                //Item区域
                Rectangle drawRect = new Rectangle(left, top, width, BasicConst);
                top += BasicConst;
    
                //Text区域
                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:允许显示字形符号的伸出部分和延伸到矩形外的未换行文本。
                //NoWrap:在矩形内设置格式时,禁用自动换行功能。
                itemTextFormat.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
                //Near:指定文本靠近布局对齐。
                itemTextFormat.Alignment = StringAlignment.Near;
                //Center:指定文本在布局矩形中居中对齐(呃,感觉不是很垂直居中,偏上了一些)。
                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,与文本的对齐效果稍微好一些。
                    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>
            /// 点击测试
            /// </summary>
            /// <param name="X">X坐标</param>
            /// <param name="Y">Y坐标</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>
            /// 是否是鼠标移过
            /// </summary>
            /// <param name="X">X坐标</param>
            /// <param name="Y">Y坐标</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>
            /// 是否是鼠标按下
            /// </summary>
            /// <param name="X">X坐标</param>
            /// <param name="Y">Y坐标</param>
            /// <returns></returns>
            public bool IsMouseDown(int X, int Y)
            {
                PopupMenuItem popupMenuItem = HitTest(X, Y);
                return popupMenuItem != null;
            }
        }
    
        /// <summary>
        /// DataGridView右键菜单自定义显示及隐藏列
        /// </summary>
        public class DataGridViewColumnSelector
        {
            private DataGridView dgvTarget = null;                      //待处理的DataGridView对象
            private ToolStripDropDown dropDown;                         //用于加载PopupMenu控件
            PopupMenuControl popupMenuControl = new PopupMenuControl(); //PopupMenu控件
    
            //无参构造函数
            public DataGridViewColumnSelector()
            {
                //注册PopupMenu控件事件
                popupMenuControl.CheckedChangedEvent += new PopupMenuControl.CheckedChanged(OnCheckedChanged);
                //使用容器承载PopupMenu控件(相当于容器类型的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);
            }
    
            //有参构造函数
            public DataGridViewColumnSelector(DataGridView dataGridView) : this()
            {
                DataGridView = dataGridView;
            }
    
            //DataGridView属性
            public DataGridView DataGridView
            {
                get { return dgvTarget; }
                set
                {
                    //去除单元格点击事件
                    if (dgvTarget != null) { dgvTarget.CellMouseClick -= new DataGridViewCellMouseEventHandler(DataGridView_CellMouseClick); }
                    dgvTarget = value;
                    //注册单元格点击事件
                    if (dgvTarget != null) { dgvTarget.CellMouseClick += new DataGridViewCellMouseEventHandler(DataGridView_CellMouseClick); }
                }
            }
    
            /// <summary>
            /// 左键点击标题栏弹出菜单
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void DataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left && e.RowIndex == -1)
                {
                    popupMenuControl.Initialize(dgvTarget);
                    //将菜单显示在光标位置
                    dropDown.Show(Cursor.Position);
                }
            }
    
            ///// <summary>
            ///// 勾选事件执行方法
            ///// </summary>
            ///// <param name="hitIndex"></param>
            ///// <param name="isCheck"></param>
            //private void OnCheckedChanged(int hitIndex, bool isChecked)
            //{
            //    dgvTarget.Columns[hitIndex].Visible = isChecked;
            //}
            /// <summary>
            /// 勾选事件执行方法
            /// </summary>
            /// <param name="hitIndex"></param>
            /// <param name="isCheck"></param>
            private void OnCheckedChanged(string itemText, bool isChecked)
            {
                //dgvTarget.Columns[hitIndex].Visible = isChecked;
                if (itemText == "全选")
                {
                    QuanXuan(isChecked);
                }
                else
                {
                    foreach (DataGridViewColumn column in dgvTarget.Columns)
                    {
                        if (column.HeaderText == itemText)
                        {
                            column.Visible = isChecked;
                            break;
                        }
                    }
                }
            }
    
            private void QuanXuan(bool isChecked)
            {
                foreach (DataGridViewColumn column in dgvTarget.Columns)
                {
                    column.Visible = isChecked;
                }
            }
        }

  • 相关阅读:
    django框架——十二
    django框架——十一
    请简述一下你所了解的数据源控件有哪些
    在ASP.NET中,<%= %>和<%# %>有什么区别
    请解释ASP.NET中的web页面与其隐藏类之间的关系
    什么是viewstate,能否禁用?是否所用控件都可以禁用
    WEB控件及HTML服务端控件能否调用客户端方法?如果能,请解释如何调用
    静态类和静态方法的好处
    请写出在ASP.NET中常用的几种页面间传值的方法,并说出它们的特点。
    连接数据库主要有哪几个对象
  • 原文地址:https://www.cnblogs.com/shuaimeng/p/15303895.html
Copyright © 2011-2022 走看看