WinForms自定义3按钮单元格

smdncfj3  于 2023-02-09  发布在  其他
关注(0)|答案(1)|浏览(180)

我正在尝试有一个自定义的DatagridViewCell,它有3个可水平单击的按钮。我已经尽我所能在如下所示的代码,但我需要一种方法来显示单元格中的3个按钮。我只能画文本到目前为止。我甚至尝试声明一个Panel对象,以防更容易地操作按钮。

public partial class CustomButtonCell : DataGridViewButtonCell
{
private Panel buttonPanel;
private Button editButton;
private Button deleteButton;
private Button approveButton;
private Button cancelButton;
public bool Enabled { get; set; }

public CustomButtonCell()
{
    this.buttonPanel = new Panel();
    this.editButton = new Button();
    this.deleteButton = new Button();
    this.approveButton = new Button();
    this.cancelButton = new Button();

    this.editButton.Text = "Edit";
    this.deleteButton.Text = "Delete";
    this.approveButton.Text = "Approve";
    this.cancelButton.Text = "Cancel";

    this.buttonPanel.Controls.Add(this.editButton);
    this.buttonPanel.Controls.Add(this.deleteButton);
    this.buttonPanel.Controls.Add(this.approveButton);
    this.buttonPanel.Controls.Add(this.cancelButton);
    this.Enabled = true;
}

// Override the Clone method so that the Enabled property is copied.
public override object Clone()
{
    CustomButtonCell cell = (CustomButtonCell )base.Clone();
    cell.Enabled = this.Enabled;
    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)
{
    // Call the base class method to paint the default cell appearance.
    base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
        value, formattedValue, errorText, cellStyle,
        advancedBorderStyle, paintParts);

    // Calculate the area in which to draw the button.
    Rectangle buttonArea1 = cellBounds;
    Rectangle buttonAdjustment = this.BorderWidths(advancedBorderStyle);
    buttonArea1.X += buttonAdjustment.X;
    buttonArea1.Y += buttonAdjustment.Y;
    buttonArea1.Height -= buttonAdjustment.Height;
    buttonArea1.Width -= buttonAdjustment.Width;
    Rectangle buttonArea2 = cellBounds;
    Rectangle buttonAdjustment2 = this.BorderWidths(advancedBorderStyle);
    buttonArea2.X += buttonAdjustment2.X + buttonArea1.Width;
    buttonArea2.Y += buttonAdjustment2.Y;
    buttonArea2.Height -= buttonAdjustment2.Height;
    buttonArea2.Width -= buttonAdjustment2.Width;
    Rectangle buttonArea3 = cellBounds;
    Rectangle buttonAdjustment3 = this.BorderWidths(advancedBorderStyle);
    buttonArea3.X += buttonAdjustment3.X + buttonArea2.Width;
    buttonArea3.Y += buttonAdjustment3.Y;
    buttonArea3.Height -= buttonAdjustment3.Height;
    buttonArea3.Width -= buttonAdjustment3.Width;
    Rectangle buttonArea4 = cellBounds;
    Rectangle buttonAdjustment4 = this.BorderWidths(advancedBorderStyle);
    buttonArea4.X += buttonAdjustment4.X + buttonArea3.Width;
    buttonArea4.Y += buttonAdjustment4.Y;
    buttonArea4.Height -= buttonAdjustment4.Height;
    buttonArea4.Width -= buttonAdjustment4.Width;
    // Draw the disabled button.
    ButtonRenderer.DrawButton(graphics, buttonArea1, PushButtonState.Default);
    ButtonRenderer.DrawButton(graphics, buttonArea2, PushButtonState.Default);
    ButtonRenderer.DrawButton(graphics, buttonArea3, PushButtonState.Default);
    ButtonRenderer.DrawButton(graphics, buttonArea4, PushButtonState.Default);

    // Draw the disabled button text.

    TextRenderer.DrawText(graphics, "Test", this.DataGridView.Font, buttonArea1, SystemColors.GrayText);
    TextRenderer.DrawText(graphics, "Test", this.DataGridView.Font, buttonArea2, SystemColors.GrayText);
    TextRenderer.DrawText(graphics, "Test", this.DataGridView.Font, buttonArea3, SystemColors.GrayText);
    TextRenderer.DrawText(graphics, "Test", this.DataGridView.Font, buttonArea4, SystemColors.GrayText);

}

// Force the cell to repaint itself when the mouse pointer enters it.
protected override void OnMouseEnter(int rowIndex)
{
   
}

// Force the cell to repaint itself when the mouse pointer leaves it.
protected override void OnMouseLeave(int rowIndex)
{
   
}

}

public class CustomButtonColumn : DataGridViewColumn
{
public CustomButtonColumn()
{
    this.CellTemplate = new CustomButtonCell ();
}
}
z2acfund

z2acfund1#

我同意有时候有一个可靠的用例来显示UserControl,无论它是“三个按钮”还是每行都有自己的滚动Chart真实的数据或其他!一个长期以来对我有效的方法,经过尝试和验证,是有一个类似于下面代码的DataGridViewUserControlColumn类,它可以在单元格边界中托管一个控件,而不仅仅是绘制一个。
操作原理是允许绑定数据类具有从Control派生的属性。DGV中的(s)可以被换出。然后,当DataGridViewUserControlCell被“绘制”而不是绘制单元格时,所发生的是控件被移动(如有必要),使其边界与正在绘制的单元格边界一致。由于用户控件位于DataGridView.Controls集合中,UC保持在z顺序的顶部,并且与任何容器的任何子容器相同地绘制。

项的UserControl在首次绘制时添加到DataGridView.Controls集合,并在单元格的DataGridView属性设置为null时(例如,用户删除行时)移除。启用AllowUserToAddRows选项时,“new row”列表项在项编辑完成之前不会显示控件。

典型记录类

class Record : INotifyPropertyChanged
{
    public Record()
    {
        Modes.TextChanged += (sender, e) =>
            OnPropertyChanged(nameof(Description));
        Actions.Click += (sender, e) =>
            { _ = execTask(); };
    }
    public string Description
    {
        get => $"{Modes.Text} : {_description}";
        set
        {
            if (!Equals(_description, value))
            {
                _description = value;
                OnPropertyChanged();
            }
        }
    }
    string _description = string.Empty;

    #region B O U N D    C O N T R O L S    o f    A N Y    T Y P E   
    public ButtonCell3Up Modes { get; } = new ButtonCell3Up();
    public ProgressBar Actions { get; } = new ProgressBar { Value = 1 };  
    #endregion B O U N D    C O N T R O L S    o f    A N Y    T Y P E   

    private async Task execTask()
    {
        Actions.Value = 0;
        while(Actions.Value < Actions.Maximum)
        {
            await Task.Delay(250);
            Actions.Value++;
        }
    }
    private void onModesTextChanged(object sender, EventArgs e) =>
        OnPropertyChanged(nameof(Description));

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

配置DGV

public partial class MainForm : Form
{
    public MainForm() => InitializeComponent();
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        dataGridView.DataSource = Records;
        dataGridView.RowTemplate.Height = 50;
        dataGridView.MouseDoubleClick += onMouseDoubleClick;  

        #region F O R M A T    C O L U M N S
        Records.Add(new Record()); // <- Auto-configure columns
        dataGridView.Columns[nameof(Record.Description)].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
        dataGridView.Columns[nameof(Record.Modes)].Width = 200;
        DataGridViewUserControlColumn.Swap(dataGridView.Columns[nameof(Record.Modes)]);
        dataGridView.Columns[nameof(Record.Actions)].Width = 200;
        dataGridView.Columns[nameof(Record.Actions)].DefaultCellStyle.Padding = new Padding(5);
        DataGridViewUserControlColumn.Swap(dataGridView.Columns[nameof(Record.Actions)]);
        Records.Clear();
        #endregion F O R M A T    C O L U M N S

        
        // FOR DEMO PURPOSES: Add some items.
        for (int i = 0; i < 5; i++)
        {
            Records.Add(new Record { Description = "Voltage Range" });
            Records.Add(new Record { Description = "Current Range" });
            Records.Add(new Record { Description = "Power Range" });
        }
        for (int i = 1; i <= Records.Count; i++)
            Records[i - 1].Modes.Labels = new[] { $"{i}A", $"{i}B", $"{i}C", }; 
}

带画图覆盖的自定义单元格

public class DataGridViewUserControlCell : DataGridViewCell
{
    private Control _control = null;
    private DataGridViewUserControlColumn _column;
    public override Type FormattedValueType => typeof(string);
    private DataGridView _dataGridView = null;
    protected override void OnDataGridViewChanged()
    {
        base.OnDataGridViewChanged();
        if((DataGridView == null) && (_dataGridView != null))
        {
            // WILL occur on Swap() and when a row is deleted.
            if (TryGetControl(out var control))
            {
                _column.RemoveUC(control);
            }
        }
        _dataGridView = DataGridView;
    }
    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)
    {
        using (var brush = new SolidBrush(getBackColor(@default: Color.Azure)))
        {
            graphics.FillRectangle(brush, cellBounds);
        }
        if (DataGridView.Rows[rowIndex].IsNewRow)
        {   /* G T K */
        }
        else
        {
            if (TryGetControl(out var control))
            {
                SetLocationAndSize(cellBounds, control);
            }
        }
        Color getBackColor(Color @default)
        {
            if((_column != null) && (_column.DefaultCellStyle != null))
            {
                Style = _column.DefaultCellStyle;
            }
            return Style.BackColor.A == 0 ? @default : Style.BackColor;
        }
    }
    public void SetLocationAndSize(Rectangle cellBounds, Control control, bool visible = true)
    {
        control.Location = new Point(
            cellBounds.Location.X +
            Style.Padding.Left,
            cellBounds.Location.Y + Style.Padding.Top);
        control.Size = new Size(
            cellBounds.Size.Width - (Style.Padding.Left + Style.Padding.Right),
            cellBounds.Height - (Style.Padding.Top + Style.Padding.Bottom));
        control.Visible = visible;
    }
    public bool TryGetControl(out Control control)
    {
        control = null;
        if (_control == null)
        {
            try
            {
                if ((RowIndex != -1) && (RowIndex < DataGridView.Rows.Count))
                {
                    var row = DataGridView.Rows[RowIndex];
                    _column = (DataGridViewUserControlColumn)DataGridView.Columns[ColumnIndex];
                    var record = row.DataBoundItem;
                    var type = record.GetType();
                    var pi = type.GetProperty(_column.Name);
                    control = (Control)pi.GetValue(record);
                    if (control.Parent == null)
                    {
                        DataGridView.Controls.Add(control);
                        _column.AddUC(control);
                    }
                }
            }
            catch (Exception ex) {
                Debug.Assert(false, ex.Message);
            }
            _control = control;
        }
        else control = _control;
        return _control != null;
    }
}

自定义列

public class DataGridViewUserControlColumn : DataGridViewColumn
{
    public DataGridViewUserControlColumn() => CellTemplate = new DataGridViewUserControlCell();
    public static void Swap(DataGridViewColumn old)
    {
        var dataGridView = old.DataGridView;
        var indexB4 = old.Index;
        dataGridView.Columns.RemoveAt(indexB4);
        dataGridView.Columns.Insert(indexB4, new DataGridViewUserControlColumn
        {
            Name = old.Name,
            AutoSizeMode = old.AutoSizeMode,
            Width = old.Width,
            DefaultCellStyle = old.DefaultCellStyle,
        });
    }
    protected override void OnDataGridViewChanged()
    {
        base.OnDataGridViewChanged();
        if ((DataGridView == null) && (_dataGridView != null))
        {
            _dataGridView.Invalidated -= (sender, e) => refresh();
            _dataGridView.Scroll -= (sender, e) => refresh();
            _dataGridView.SizeChanged -= (sender, e) => refresh();
            foreach (var control in _controls.ToArray())
            {
                RemoveUC(control);
            }
        }
        else
        {
            DataGridView.Invalidated += (sender, e) =>refresh();
            DataGridView.Scroll += (sender, e) =>refresh();
            DataGridView.SizeChanged += (sender, e) =>refresh();
        }
        _dataGridView = DataGridView;
    }
    // Keep track of controls added by this instance
    // so that they can be removed by this instance.
    private readonly List<Control> _controls = new List<Control>();
    internal void AddUC(Control control)
    {
        _controls.Add(control);
        DataGridView.Controls.Add(control);
    }
    internal void RemoveUC(Control control)
    {
        _controls.Remove(control);
        if (_dataGridView != null)
        {
            _dataGridView.Controls.Remove(control);
        }
    }
    int _wdtCount = 0;
    private void refresh()
    {
        var capture = ++_wdtCount;
        // Allow changes to settle.
        Task
            .Delay(TimeSpan.FromMilliseconds(10))
            .GetAwaiter()
            .OnCompleted(() => 
            {
                if (DataGridView != null)
                {
                    foreach (var row in DataGridView.Rows.Cast<DataGridViewRow>().ToArray())
                    {
                        if (row.Cells[Index] is DataGridViewUserControlCell cell)
                        {
                            if (row.IsNewRow)
                            {   /* G T K */
                            }
                            else
                            {
                                var cellBounds = DataGridView.GetCellDisplayRectangle(cell.ColumnIndex, cell.RowIndex, true);
                                if (cell.TryGetControl(out var control))
                                {
                                    cell.SetLocationAndSize(cellBounds, control, visible: !row.IsNewRow);
                                }
                            }
                        }
                    }
                }
            });
    }
    private DataGridView _dataGridView = null;
}

相关问题