为每个单元格添加带有标签和按钮的自定义 DataGridViewColumn [英] add custom DataGridViewColumn with label and button per cell

查看:29
本文介绍了为每个单元格添加带有标签和按钮的自定义 DataGridViewColumn的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将自定义 DataGridViewColumn 添加到我的 DataGridView.此列应每行创建以下单元格

起初我创建了一个自定义的UserControl,它创建了一个带有按钮的标签.

 私有类 AllocationControl : UserControl{public AllocationControl(IndexField[] indexFields, BatchField[] batchFields){标签 lbl = new Label();Controls.Add(lbl);ContextMenuStrip contextMenu = new ContextMenuStrip();//填充菜单Controls.Add(contextMenu);Button btn = new Button();btn.Click += (object sender, EventArgs e) =>{contextMenu.Show(Cursor.Position);};Controls.Add(btn);}公共字符串 DisplayedName { 获取;私人订制;}公共双 SelectedID { 获取;私人订制;}}

我必须将一些数据作为构造函数参数传入,但这与问题无关.

之后我创建了一个自定义的DataGridViewCell

 私有类 DataGridViewAllocationCell : DataGridViewCell{公共 DataGridViewAllocationCell(){}protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts){AllocationControl allocationControl = value as AllocationControl;Bitmap allocationControlImage = new Bitmap(cellBounds.Width, cellBounds.Height);allocationControl.DrawToBitmap(allocationControlImage, new Rectangle(0, 0, allocationControl.Width, allocationControl.Height));graphics.DrawImage(allocationControlImage, cellBounds.Location);}}

此单元格应保留自定义控件并显示它.

最后,我通过设置 CellTemplate

将此单元格添加到我的自定义 DataGridViewColumn

 私有类 DataGridViewAllocationColumn : DataGridViewColumn{公共 DataGridViewAllocationColumn(){CellTemplate = new DataGridViewAllocationCell();}}

我的问题是如何将 UserControl 分配给 DataGridViewCell?

我接受了这份指南

自定义列具有 LabelTextButtonText 属性.当您单击按钮部分时,它会显示您分配给相应属性的 ContextMenuStrip.

<块引用>

注意:这只是一个示例,根据要求,您可能希望更改属性、呈现逻辑和显示菜单的方式或其他任何东西.但我认为这是一个很好的起点.

代码如下:

使用 System.Drawing;使用 System.Windows.Forms;公共类 DataGridViewAllocationControlColumn : DataGridViewButtonColumn{公共 DataGridViewAllocationControlColumn(){this.CellTemplate = new DataGridViewAllocationControlCell();}公共字符串 LabelText { 获取;放;}公共字符串 ButtonText { 获取;放;}公共覆盖对象 Clone(){var c = (DataGridViewAllocationControlColumn)base.Clone();c.LabelText = this.LabelText;c.ButtonText = this.ButtonText;返回 c;}}公共类 DataGridViewAllocationControlCell : DataGridViewButtonCell{protected override void Paint(Graphics graphics, Rectangle clipBounds,矩形 cellBounds,int rowIndex,DataGridViewElementStates elementState,对象值,对象 formattedValue,字符串 errorText,DataGridViewCellStyle 单元格样式,DataGridViewAdvancedBorderStyle advancedBorderStyle,DataGridViewPaintPartspaintParts){var g = this.DataGridView;var c = (DataGridViewAllocationControlColumn)this.OwningColumn;base.Paint(图形,clipBounds,cellBounds,rowIndex,elementState,值、formattedValue、errorText、cellStyle、advancedBorderStyle、DataGridViewPaintParts.All &~DataGridViewPaintParts.ContentBackground &~DataGridViewPaintParts.ContentForeground);var r1 = g.GetCellDisplayRectangle(c.Index, rowIndex, false);var r2 = GetContentBounds(rowIndex);var r3 = new Rectangle(r1.Location, new Size(GetLabelWidth(), r1.Height));r2.Offset(r1.Location);base.Paint(图形,clipBounds,r2,rowIndex,elementState,值,c.ButtonText,errorText,cellStyle,advancedBorderStyle,DataGridViewPaintParts.All);TextRenderer.DrawText(graphics, c.LabelText, cellStyle.Font,r3, cellStyle.ForeColor);}受保护的覆盖矩形 GetContentBounds(图形图形,DataGridViewCellStyle cellStyle, int rowIndex){var w = GetLabelWidth();var r = base.GetContentBounds(graphics, cellStyle, rowIndex);return new Rectangle(r.Left + w, r.Top, r.Width - w, r.Height);}protected override void OnContentClick(DataGridViewCellEventArgs e){base.OnContentClick(e);var g = this.DataGridView;var c = (DataGridViewAllocationControlColumn)this.OwningColumn;var r1 = GetContentBounds(e.RowIndex);var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);var p = new Point(r2.Left + r1.Left, r2.Top + r1.Bottom);if (c.ContextMenuStrip != null)c.ContextMenuStrip.Show(g, p);}私有 int GetLabelWidth(){var c = (DataGridViewAllocationControlColumn)this.OwningColumn;var text = c.LabelText;返回 TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width;}}

I want to add a custom DataGridViewColumn to my DataGridView. This column should create the following cell per row

At first I created a custom UserControl that creates a label with a button.

    private class AllocationControl : UserControl
    {
        public AllocationControl(IndexField[] indexFields, BatchField[] batchFields)
        {
            Label lbl = new Label();
            Controls.Add(lbl);

            ContextMenuStrip contextMenu = new ContextMenuStrip();
            // fill the menu
            Controls.Add(contextMenu);

            Button btn = new Button();
            btn.Click += (object sender, EventArgs e) =>
            {
                contextMenu.Show(Cursor.Position);
            };
            Controls.Add(btn);
        }

        public string DisplayedName { get; private set; }
        public double SelectedID { get; private set; }
    }

I have to pass in some data as constructor parameters but this is not relevant for the question.

After that I create a custom DataGridViewCell

    private class DataGridViewAllocationCell : DataGridViewCell
    {
        public DataGridViewAllocationCell()
        {
        }

        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            AllocationControl allocationControl = value as AllocationControl;
            Bitmap allocationControlImage = new Bitmap(cellBounds.Width, cellBounds.Height);
            allocationControl.DrawToBitmap(allocationControlImage, new Rectangle(0, 0, allocationControl.Width, allocationControl.Height));
            graphics.DrawImage(allocationControlImage, cellBounds.Location);
        }
    }

This cell should keep the custom control and display it.

At the end I add this cell to my custom DataGridViewColumn by setting the CellTemplate

    private class DataGridViewAllocationColumn : DataGridViewColumn
    {
        public DataGridViewAllocationColumn()
        {
            CellTemplate = new DataGridViewAllocationCell();
        }
    }

My question is how can I assign the UserControl to the DataGridViewCell?

I took this guide

https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-host-controls-in-windows-forms-datagridview-cells

but they all show up how to create a single control and put it into a cell. I have to setup three controls (label, button and contextMenu) within one cell.

解决方案

There are 3 main pillars for a new column type:

  • DataGridViewColumn is responsible for properties which you set in design mode in column editor of the control.
  • DataGridViewCell is responsible for appearance of the cell. It renders the value and other painting parts in cell and initialize the editing control (if the column has any editing control).
  • DataGridViewEditingControl is responsible for editing the value of the cell.

When creating a new column you can derive from DataGridViewColumn or one of its derived classes. Also when creating a new cell for the column, you can derive from DataGridViewCell or one of its derived classes. Also when creating a new editing control, you can derive from one of the existing editing controls, or you can start by deriving from a control class and implementing IDataGridViewEditingControl interface.

Keep in mind, the editing control will be shown just in the editing cell. Rest of cells show what you render in the paint method of the cell.

Example

Here in this post, I've shared an example of drawing a custom cell containing a label and a button. I've not created an editing control because for this example, we can derive from DataGridViewButtonColumn and DataGridViewButtonCell without needing to create an editing control. We just add some properties to column and change paint logic and override OnContentClick to show the context menu, like this:

The custom column has LabelText and ButtonText properties. When you click on the button part, it shows the ContextMenuStrip which you assigned to corresponding property.

Note: This is just an example and depending on the requirements, you may want to change properties, rendering logic and the way that you show menu or anything else. But I think it's a good start point.

Here is the code:

using System.Drawing;
using System.Windows.Forms;
public class DataGridViewAllocationControlColumn : DataGridViewButtonColumn
{
    public DataGridViewAllocationControlColumn()
    {
        this.CellTemplate = new DataGridViewAllocationControlCell();
    }
    public string LabelText { get; set; }
    public string ButtonText { get; set; }
    public override object Clone()
    {
        var c = (DataGridViewAllocationControlColumn)base.Clone();
        c.LabelText = this.LabelText;
        c.ButtonText = this.ButtonText;
        return c;
    }
}
public class DataGridViewAllocationControlCell : DataGridViewButtonCell
{
    protected override void Paint(Graphics graphics, Rectangle clipBounds,
        Rectangle cellBounds, int rowIndex, 
        DataGridViewElementStates elementState,
        object value, object formattedValue, string errorText,
        DataGridViewCellStyle cellStyle,
        DataGridViewAdvancedBorderStyle advancedBorderStyle,
        DataGridViewPaintParts paintParts)
    {
        var g = this.DataGridView;
        var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
            value, formattedValue, errorText, cellStyle, advancedBorderStyle,
            DataGridViewPaintParts.All &
            ~DataGridViewPaintParts.ContentBackground &
            ~DataGridViewPaintParts.ContentForeground);
        var r1 = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
        var r2 = GetContentBounds(rowIndex);
        var r3 = new Rectangle(r1.Location, new Size(GetLabelWidth(), r1.Height));
        r2.Offset(r1.Location);
        base.Paint(graphics, clipBounds, r2, rowIndex, elementState,
            value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
            DataGridViewPaintParts.All);
        TextRenderer.DrawText(graphics, c.LabelText, cellStyle.Font,
            r3, cellStyle.ForeColor);
    }
    protected override Rectangle GetContentBounds(Graphics graphics, 
        DataGridViewCellStyle cellStyle, int rowIndex)
    {
        var w = GetLabelWidth();
        var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
        return new Rectangle(r.Left + w, r.Top, r.Width - w, r.Height);
    }
    protected override void OnContentClick(DataGridViewCellEventArgs e)
    {
        base.OnContentClick(e);
        var g = this.DataGridView;
        var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
        var r1 = GetContentBounds(e.RowIndex);
        var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
        var p = new Point(r2.Left + r1.Left, r2.Top + r1.Bottom);
        if (c.ContextMenuStrip != null)
            c.ContextMenuStrip.Show(g, p);
    }
    private int GetLabelWidth()
    {
        var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
        var text = c.LabelText;
        return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width;
    }
}

这篇关于为每个单元格添加带有标签和按钮的自定义 DataGridViewColumn的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆