在每个单元格中添加带有标签和按钮的自定义DataGridViewColumn

时间:2018-11-08 11:02:55

标签: c# winforms

我想向DataGridViewColumn中添加自定义DataGridView。此列应每行创建以下单元格

img

首先,我创建了一个自定义UserControl,该按钮创建了一个带有按钮的标签。

    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; }
    }

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

此后,我创建了一个自定义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);
        }
    }

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

最后,我通过设置DataGridViewColumn

将此单元格添加到自定义CellTemplate
    private class DataGridViewAllocationColumn : DataGridViewColumn
    {
        public DataGridViewAllocationColumn()
        {
            CellTemplate = new DataGridViewAllocationCell();
        }
    }

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

我接受了本指南

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

但是它们都显示了如何创建单个控件并将其放入单元格中。我必须在一个单元格内设置三个控件(标签,按钮和contextMenu)。

2 个答案:

答案 0 :(得分:1)

对于一种新的列类型,有3个主要支柱:

  • DataGridViewColumn负责在控件的列编辑器中的设计模式下设置的属性。
  • DataGridViewCell负责单元的外观。它将值和其他绘画部分渲染到单元格中,并初始化编辑控件(如果该列具有任何编辑控件)。
  • DataGridViewEditingControl负责编辑单元格的值。

创建新列时,可以从DataGridViewColumn或其派生类之一派生。同样,在为该列创建新单元格时,您可以从DataGridViewCell或其派生类之一派生。同样,在创建新的编辑控件时,可以从现有的编辑控件之一派生,也可以从控件类派生并实现IDataGridViewEditingControl接口开始。

请记住,编辑控件将仅显示在编辑单元格中。其余单元格显示您使用单元格的paint方法渲染的内容。

示例

在本文中,我分享了一个绘制包含标签和按钮的自定义单元格的示例。我尚未创建编辑控件,因为在此示例中,我们可以从DataGridViewButtonColumnDataGridViewButtonCell派生而无需创建编辑控件。我们只是向列添加一些属性,并更改绘制逻辑并覆盖OnContentClick以显示上下文菜单,如下所示:

enter image description here

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

  

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

代码如下:

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;
    }
}

答案 1 :(得分:0)

我采用了这段代码并将其修改为更具动态性,这对我来说是一个很好的起点,对此我感到非常感谢。我希望能够使用按钮选择一个文件夹,然后单击链接打开该文件夹。

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Forms.VisualStyles;
using System.IO;

namespace Project
{

public class LinkButtonColumn : DataGridViewButtonColumn
{
    private EventHandler<DataGridViewCellMouseEventArgs> buttonClickHandler;
    private EventHandler<DataGridViewCellMouseEventArgs> linkClickHandler;
    public LinkButtonColumn()
    {
        this.CellTemplate = new DataGridViewLinkButtonCell();
    }

    public override DataGridViewCell CellTemplate
    {
        get
        {
            return base.CellTemplate;
        }
        set
        {
            base.CellTemplate = value;
            DataGridViewLinkButtonCell cell = CellTemplate as DataGridViewLinkButtonCell;
            if (cell != null)
                cell.ButtonClickHandler = ButtonClickHandler;
            cell.LinkClickHandler = LinkClickHandler;
            

        }
    }

    public EventHandler<DataGridViewCellMouseEventArgs> LinkClickHandler
    {
        get
        {
            return linkClickHandler;
        }
        set
        {
            DataGridViewLinkButtonCell cell = CellTemplate as DataGridViewLinkButtonCell;
            if (cell != null)
            {
                if (value != null)
                    cell.LinkClickHandler += value;
                else if (linkClickHandler != null)
                    cell.LinkClickHandler -= linkClickHandler;
            }
            linkClickHandler = value;
        }
    }

    public EventHandler<DataGridViewCellMouseEventArgs> ButtonClickHandler
    {
        get
        {
            return buttonClickHandler;
        }
        set
        {
            DataGridViewLinkButtonCell cell = CellTemplate as DataGridViewLinkButtonCell;
            if (cell != null)
            {
                if (value != null)
                    cell.ButtonClickHandler += value;
                else if (buttonClickHandler != null)
                    cell.ButtonClickHandler -= buttonClickHandler;
            }
            buttonClickHandler = value;
        }
    }

}
internal sealed class DataGridViewLinkButtonColumn : DataGridViewColumn
{
    private EventHandler<DataGridViewCellMouseEventArgs> buttonClickHandler;
    private EventHandler<DataGridViewCellMouseEventArgs> linkClickHandler;
    public string LabelText { get; set; }
    public string ButtonText { get; set; }
    public override object Clone()
    {
        var c = (DataGridViewLinkButtonColumn)base.Clone();
        c.LabelText = this.LabelText;
        c.ButtonText = this.ButtonText;
        return c;
    }
    public DataGridViewLinkButtonColumn() : base(new DataGridViewLinkButtonCell())
    {
    }

    public EventHandler<DataGridViewCellMouseEventArgs> LinkClickHandler
    {
        get
        {
            return linkClickHandler;
        }
        set
        {
            DataGridViewLinkButtonCell cell = CellTemplate as DataGridViewLinkButtonCell;
            if (cell != null)
            {
                if (value != null)
                    cell.LinkClickHandler += value;
                else if (linkClickHandler != null)
                    cell.LinkClickHandler -= linkClickHandler;
            }
            linkClickHandler = value;
        }
    }

    public EventHandler<DataGridViewCellMouseEventArgs> ButtonClickHandler
    {
        get
        {
            return buttonClickHandler;
        }
        set
        {
            DataGridViewLinkButtonCell cell = CellTemplate as DataGridViewLinkButtonCell;
            if (cell != null)
            {
                if (value != null)
                    cell.ButtonClickHandler += value;
                else if (buttonClickHandler != null)
                    cell.ButtonClickHandler -= buttonClickHandler;
            }
            buttonClickHandler = value;
        }
    }
}

public class DataGridViewLinkButtonCell : DataGridViewButtonCell
{
    private Rectangle clickRectangleValue = new Rectangle();
    private string buttonPosion = "Middle";
    public EventHandler<DataGridViewCellMouseEventArgs> ButtonClickHandler { get; set; }
    public EventHandler<DataGridViewCellMouseEventArgs> LinkClickHandler { get; set; }

    public Rectangle ClickRectangle
    {
        get
        {
            Rectangle newRect = new Rectangle();
            switch (buttonPosion)
            {
                case "Bottom":
                    newRect = new Rectangle(clickRectangleValue.X + clickRectangleValue.Width - 20, clickRectangleValue.Y + (clickRectangleValue.Height - 20), 20, 20);
                    break;
                case "Middle":
                    newRect = new Rectangle(clickRectangleValue.X + clickRectangleValue.Width - 20, clickRectangleValue.Y + ((clickRectangleValue.Height - 20) / 2), 20, 20);
                    break;
                case "Top":
                    newRect = new Rectangle(clickRectangleValue.X + clickRectangleValue.Width - 20, clickRectangleValue.Y, 20, 20);                        
                    break;
            }
            

            return newRect;
        }
    }

    public override object Clone()
    {
        DataGridViewLinkButtonCell cell = base.Clone() as DataGridViewLinkButtonCell;
        if (cell != null)
        {
            cell.ButtonClickHandler = ButtonClickHandler;
            cell.LinkClickHandler = LinkClickHandler;
        }
        return cell;
    }

    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 = (DataGridViewLinkButtonColumn)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);
        

        
        Color forecolor = Color.Black;
        TextFormatFlags horizontal = TextFormatFlags.HorizontalCenter;
        TextFormatFlags vertical = TextFormatFlags.VerticalCenter;
        switch (cellStyle.Alignment)
        {
            case DataGridViewContentAlignment.BottomCenter:
                horizontal = TextFormatFlags.HorizontalCenter;
                vertical = TextFormatFlags.Bottom;
                break;
            case DataGridViewContentAlignment.BottomLeft:
                horizontal = TextFormatFlags.Left;
                vertical = TextFormatFlags.Bottom;
                break;
            case DataGridViewContentAlignment.BottomRight:
                horizontal = TextFormatFlags.Right;
                vertical = TextFormatFlags.Bottom;
                break;
            case DataGridViewContentAlignment.MiddleCenter:
                horizontal = TextFormatFlags.HorizontalCenter;
                vertical = TextFormatFlags.VerticalCenter;
                break;
            case DataGridViewContentAlignment.MiddleLeft:
                horizontal = TextFormatFlags.Left;
                vertical = TextFormatFlags.VerticalCenter;
                break;
            case DataGridViewContentAlignment.MiddleRight:
                horizontal = TextFormatFlags.Right;
                vertical = TextFormatFlags.VerticalCenter;
                break;
            case DataGridViewContentAlignment.TopCenter:
                horizontal = TextFormatFlags.HorizontalCenter;
                vertical = TextFormatFlags.Top;
                break;
            case DataGridViewContentAlignment.TopLeft:
                horizontal = TextFormatFlags.Left;
                vertical = TextFormatFlags.Top;
                break;
            case DataGridViewContentAlignment.TopRight:
                horizontal = TextFormatFlags.Right;
                vertical = TextFormatFlags.Top;
                break;
        }


        if (g.Rows[rowIndex].Cells[c.Index].Selected)
        {
            if (value != null)
            {
                if (Directory.Exists(value.ToString()) || File.Exists(value.ToString()))
                {
                    forecolor = Color.Red;
                    TextRenderer.DrawText(graphics, value.ToString(), new Font(cellStyle.Font, FontStyle.Underline),
                  r1, forecolor, Color.Empty,
                  horizontal |
                  vertical |
                  TextFormatFlags.TextBoxControl |
                  TextFormatFlags.WordBreak |
                  TextFormatFlags.EndEllipsis);
                }
                else
                {
                    forecolor = Color.Blue;
                    TextRenderer.DrawText(graphics, value.ToString(), new Font(cellStyle.Font, FontStyle.Regular),
                  r1, Color.White, Color.Empty,
                  horizontal |
                  vertical |
                  TextFormatFlags.TextBoxControl |
                  TextFormatFlags.WordBreak |
                  TextFormatFlags.EndEllipsis);
                }
            }
        }
        else
        {
            if (value != null)
            {
                if (Directory.Exists(value.ToString()) || File.Exists(value.ToString()))
                {
                    forecolor = Color.Blue;
                    TextRenderer.DrawText(graphics, value.ToString(), new Font(cellStyle.Font, FontStyle.Underline),
                  r1, forecolor, Color.Empty,
                  horizontal |
                  vertical |
                  TextFormatFlags.TextBoxControl |
                  TextFormatFlags.WordBreak |
                  TextFormatFlags.EndEllipsis);
                }
                else
                {
                    forecolor = Color.Blue;
                    TextRenderer.DrawText(graphics, value.ToString(), new Font(cellStyle.Font, FontStyle.Regular),
                  r1, Color.Black, Color.Empty, 
                  horizontal |
                  vertical |
                  TextFormatFlags.TextBoxControl |
                  TextFormatFlags.WordBreak |
                  TextFormatFlags.EndEllipsis);
                }
            }
        }

        

        Point cursorPosition = this.DataGridView.PointToClient(Cursor.Position);

        
        if (cellBounds.Contains(cursorPosition))
        {
            clickRectangleValue = cellBounds;
            Rectangle newRect = new Rectangle(cellBounds.X + 1,
                cellBounds.Y + 1, cellBounds.Width - 4,
                cellBounds.Height - 4);
            DataGridViewCellStyle style = cellStyle;
            style.Alignment = DataGridViewContentAlignment.MiddleCenter;
            base.Paint(graphics, clipBounds, ClickRectangle, rowIndex, elementState,
            value, c.ButtonText, errorText, style, advancedBorderStyle,
            DataGridViewPaintParts.All);
        }
        
    }
    protected override Rectangle GetContentBounds(Graphics graphics,
        DataGridViewCellStyle cellStyle, int rowIndex)
    {
        
        var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
        switch (cellStyle.Alignment)
        {
            case DataGridViewContentAlignment.BottomCenter:
                buttonPosion = "Bottom";
                break;
            case DataGridViewContentAlignment.BottomLeft:
                buttonPosion = "Bottom";
                break;
            case DataGridViewContentAlignment.BottomRight:
                buttonPosion = "Bottom";
                break;
            case DataGridViewContentAlignment.MiddleCenter:
                buttonPosion = "Middle";
                break;
            case DataGridViewContentAlignment.MiddleLeft:
                buttonPosion = "Middle";
                break;
            case DataGridViewContentAlignment.MiddleRight:
                buttonPosion = "Middle";
                break;
            case DataGridViewContentAlignment.TopCenter:
                buttonPosion = "Top";
                break;
            case DataGridViewContentAlignment.TopLeft:
                buttonPosion = "Top";
                break;
            case DataGridViewContentAlignment.TopRight:
                buttonPosion = "Top";
                break;
        }
        clickRectangleValue = r;
        
        return new Rectangle(ClickRectangle.X, ClickRectangle.Y, ClickRectangle.Width, ClickRectangle.Height);
    }
        

    protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
    {
        int x = e.X;
        int y = e.Y;

        Point cursorPosition = this.DataGridView.PointToClient(Cursor.Position);

        var g = this.DataGridView;
        var r1 = GetContentBounds(e.RowIndex);
        var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
        r1.X = r1.X + r2.X;
        r1.Y = r1.Y + r2.Y;
        if (r1.Contains(cursorPosition))
        {                
            if (ButtonClickHandler != null)
            {
                this.ButtonClickHandler.Invoke(this,e); 
            }
        }
        else
        {
            if (r2.Contains(cursorPosition))
            {
                if (LinkClickHandler != null)
                {
                    this.LinkClickHandler.Invoke(this, e);
                }
            }
        }
        
    }
    
    protected override void OnMouseEnter(int rowIndex)
    {
        Cursor.Current = Cursors.Hand;
        this.DataGridView.Cursor = Cursor.Current;
        this.DataGridView.InvalidateCell(this);
        
    }
    
    protected override void OnMouseLeave(int rowIndex)
    {
        this.DataGridView.InvalidateCell(this);
        Cursor.Current = Cursors.Default;
        this.DataGridView.Cursor = Cursor.Current;
    }
}
}

然后我实用地将列添加到网格中。

if (!Addendum_dataGridView.Columns.Contains("Folder_Location"))
    {
    DataGridViewLinkButtonColumn textButtonColumn = new DataGridViewLinkButtonColumn();

    textButtonColumn.ValueType = typeof(string);
    textButtonColumn.HeaderText = "Folder Location";
    textButtonColumn.ButtonText = "...";
    textButtonColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
    textButtonColumn.DefaultCellStyle.Padding = new Padding(1, 0, 0, 0);
    textButtonColumn.Width = 100;
    textButtonColumn.Name = "Folder_Location";
    textButtonColumn.DataPropertyName = "Folder_Location";           
    textButtonColumn.LinkClickHandler = (o, e) =>
     {
     if(Addendum_dataGridView.Rows[e.RowIndex].Cells[Addendum_dataGridView.Columns["Folder_Location"].Index].Value != DBNull.Value)
     { 
         if (Directory.Exists(Addendum_dataGridView.Rows[e.RowIndex].Cells[Addendum_dataGridView.Columns["Folder_Location"].Index].Value.ToString()) || File.Exists(Addendum_dataGridView.Rows[e.RowIndex].Cells[Addendum_dataGridView.Columns["Folder_Location"].Index].Value.ToString()))
         {
         Process.Start(Addendum_dataGridView.Rows[e.RowIndex].Cells[Addendum_dataGridView.Columns["Folder_Location"].Index].Value.ToString());
         }
     }
     };
    textButtonColumn.ButtonClickHandler = (o, e) =>
    {
    CommonOpenFileDialog cofd = new CommonOpenFileDialog();
    cofd.IsFolderPicker = true;
    cofd.Multiselect = false;
    cofd.Title = "Select Addendum Folder";
    if (Addendum_dataGridView.Rows[e.RowIndex].Cells[Addendum_dataGridView.Columns["Folder_Location"].Index].Value != DBNull.Value)
    {
        cofd.InitialDirectory = Addendum_dataGridView.Rows[e.RowIndex].Cells[Addendum_dataGridView.Columns["Folder_Location"].Index].Value.ToString();
    }
    else
    {
        cofd.InitialDirectory = Directory.GetParent(Directory.GetParent(SQL_Commands.Get_Data("select top 1 Quote_Location from [Index].[Estimates_Project_info] where Project_ID = " + P_ID).FirstOrDefault()).ToString()).ToString();
    }
    if (cofd.ShowDialog() == CommonFileDialogResult.Ok)
    {
        if (Addendum_dataGridView.Rows[e.RowIndex].IsNewRow)
        {
            int r = Addendum_dataGridView.NewRowIndex;
            DataTable dt = Addendum_dataGridView.DataSource as DataTable;

            DataRow row = dt.NewRow();

            row["Addendum_Number"] = Path.GetFileNameWithoutExtension(cofd.FileName.ToString());
            row["Folder_Location"] = cofd.FileName.ToString();

            dt.Rows.Add(row);
            dt = Addendum_dataGridView.DataSource as DataTable;

            bool blank = true;
            DataGridViewRow dgvr = Addendum_dataGridView.Rows[Addendum_dataGridView.Rows.Count - 2];
            for (int i = 0; i < Addendum_dataGridView.ColumnCount;i++)
            {
                if (dgvr.Cells[i].Value != DBNull.Value)
                {
                    blank = false;
                }
        }

        if (blank)
        {
            Addendum_dataGridView.Rows.RemoveAt(Addendum_dataGridView.Rows.Count - 2);
        }

        insert_Addendum = true;
        Addendum_Data_Update(r);
    }
    else
    {
        Addendum_dataGridView["Folder_Location",e.RowIndex].Value = cofd.FileName.ToString();Addendum_dataGridView.Rows[e.RowIndex].Cells[Addendum_dataGridView.Columns["Folder_Location"].Index].Selected = true;
        Addendum_Data_Update(e.RowIndex);
    }
    }

    };
Addendum_dataGridView.Columns.Insert(Addendum_dataGridView.Columns.Count,textButtonColumn);
}