DataGridViewDisableButtonCell
要讓 DataGridViewButtonColumn 有無法使用或是隱藏效果,其實是透過 Paint 繪製 DataGridViewButtonColumn 外觀去變化,DataGridViewButtonCell 內會自訂 CellEnabled 和 CellVisible 來開放控制,Paint 事件內根據這兩個 Property 去判斷如何繪製外觀,另外因為是從繼承 DataGridViewButtonCell,所以要覆寫 Clone 並把 CellEnabled 和 CellVisible 塞進去,文件上也有特別說明該點
When you derive from DataGridViewCell or DataGridViewColumn and add new properties to the derived class, be sure to override the Clone method to copy the new properties during cloning operations. You should also call the base class's Clone method so that the properties of the base class are copied to the new cell or column.
using System.Windows.Forms.VisualStyles;
namespace DataGridViewDisableButtonColumnSample
{
public class DataGridViewDisableButtonCell : DataGridViewButtonCell
{
public bool CellEnabled { get; set; } = true;
public bool CellVisible { get; set; } = true;
public DataGridViewDisableButtonCell()
{
// 預設值
CellEnabled = true;
CellVisible = true;
}
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)
{
// 計算 Cell 內繪製 Button 區域
Rectangle buttonArea = cellBounds;
Rectangle buttonAdjustment = BorderWidths(advancedBorderStyle);
buttonArea.X += buttonAdjustment.X;
buttonArea.Y += buttonAdjustment.Y;
buttonArea.Height -= buttonAdjustment.Height;
buttonArea.Width -= buttonAdjustment.Width;
using SolidBrush cellBackground = new SolidBrush(cellStyle.BackColor);
if (CellVisible == false)
{
// 把整個背景 Cell 都繪製為背景色,讓使用者以為沒有 Button 控件
graphics.FillRectangle(cellBackground, buttonArea);
}
else if (CellEnabled == false)
{
if (paintParts.HasFlag(DataGridViewPaintParts.Background))
graphics.FillRectangle(cellBackground, cellBounds);
if (paintParts.HasFlag(DataGridViewPaintParts.Border))
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
ButtonRenderer.DrawButton(graphics, buttonArea, PushButtonState.Disabled);
if (FormattedValue is string)
{
TextRenderer.DrawText(graphics,
(string)FormattedValue,
DataGridView.Font,
buttonArea,
SystemColors.GrayText);
}
}
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
}
}
public override object Clone()
{
DataGridViewDisableButtonCell cell = (DataGridViewDisableButtonCell)base.Clone();
cell.CellEnabled = CellEnabled;
cell.CellVisible = CellVisible;
return cell;
}
}
}
DataGridViewDisableButtonColumn
很單純把 CellTemplate 指定使用 DataGridViewDisableButtonCell 而已
主程式
namespace DataGridViewDisableButtonColumnSample
{
public class DataGridViewDisableButtonColumn : DataGridViewButtonColumn
{
public DataGridViewDisableButtonColumn()
{
CellTemplate = new DataGridViewDisableButtonCell();
}
}
}
主程式
觸發 CellValueChanged 事件,要特別指定重新繪製 DataGridViewButtonColumn 外觀,可以使用
- Invalidate()
- InvalidateColumn()
- Refresh()
以上都可以達到重新繪製 DataGridViewButtonColumn 目的,該筆記是從最小單位繪製去思考,所以使用 InvalidateColumn()
namespace DataGridViewDisableButtonColumnSample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
dataGridView1.AutoSize = true;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
dataGridView1.RowCount = 8;
for (int i = 0; i < dataGridView1.RowCount; i++)
dataGridView1.Rows[i].Cells[ColButtonEnabled.Index].Value = $"Button{i}";
dataGridView1.CellValueChanged += DataGridView1_CellValueChanged;
dataGridView1.CurrentCellDirtyStateChanged += DataGridView1_CurrentCellDirtyStateChanged;
dataGridView1.CellClick += DataGridView1_CellClick;
}
private void DataGridView1_CellClick(object? sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex != ColButtonEnabled.Index)
return;
DataGridViewDisableButtonCell buttonEnabled = (DataGridViewDisableButtonCell)dataGridView1.Rows[e.RowIndex].Cells[ColButtonEnabled.Index];
if (buttonEnabled.CellEnabled == false)
return;
MessageBox.Show($"{buttonEnabled.Value} 是 Enabled");
}
private void DataGridView1_CurrentCellDirtyStateChanged(object? sender, EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty &&
dataGridView1.CurrentCell.ColumnIndex == ColChecked.Index)
// CommitEdit() 會維持在編輯模式,並立即觸發 CellValueChanged 事件
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void DataGridView1_CellValueChanged(object? sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex != ColChecked.Index)
return;
bool value = (bool)dataGridView1.Rows[e.RowIndex].Cells[ColChecked.Index].Value;
DataGridViewDisableButtonCell buttonEnabled = (DataGridViewDisableButtonCell)dataGridView1.Rows[e.RowIndex].Cells[ColButtonEnabled.Index];
buttonEnabled.CellEnabled = !value;
DataGridViewDisableButtonCell buttonVisible = (DataGridViewDisableButtonCell)dataGridView1.Rows[e.RowIndex].Cells[ColButtonVisible.Index];
buttonVisible.CellVisible = !value;
dataGridView1.InvalidateColumn(ColButtonEnabled.Index);
dataGridView1.InvalidateColumn(ColButtonVisible.Index);
}
}
}
- 延伸閱讀
- [C#] 繪製文字
沒有留言:
張貼留言