C# DataGridViewRadioButtonColumn
单元格:

/// <summary> /// radio button单元格 /// </summary> /// <remarks>绑定数据后不能在构造函数中修改属性</remarks> public class DataGridViewRadioButtonCell : DataGridViewTextBoxCell { Point radioButtonLocation; Size radioButtonSize; Point _cellLocation = new Point(); System.Windows.Forms.VisualStyles.RadioButtonState _cbState = System.Windows.Forms.VisualStyles.RadioButtonState.UncheckedNormal; #region Property #region 行为 private DataGridViewTriState _isReadOnly = DataGridViewTriState.NotSet; /// <summary> /// 是否只读 /// </summary> [Category("行为")] [Description("是否只读")] [DefaultValue(DataGridViewTriState.NotSet)] [Browsable(false)] public DataGridViewTriState IsReadOnly { get { if (_isReadOnly == DataGridViewTriState.NotSet) { if (this.OwningColumn != null && OwningColumn is DataGridViewRadioButtonColumn) { _isReadOnly = (this.OwningColumn as DataGridViewRadioButtonColumn).IsReadOnly ? DataGridViewTriState.True : DataGridViewTriState.False; } } return _isReadOnly; } set { if (value == DataGridViewTriState.NotSet) { value = DataGridViewTriState.False; } _isReadOnly = value; } } /// <summary> /// 不允许编辑 /// </summary> [Browsable(false)] [DefaultValue(true)] public override bool ReadOnly { get { return true; } set { base.ReadOnly = true; } } private bool _isChecked = false; /// <summary> /// 是否选中 /// </summary> [Category("行为")] [Description("是否选中")] [DefaultValue(false)] [RefreshProperties(RefreshProperties.Repaint)] public bool Checked { get { return _isChecked; } set { //重新界定值 base.Value = value ? "1" : "0"; if (_isChecked != value) { _isChecked = value; if (value && this.OwningColumn != null && this.DataGridView != null && this.OwningColumn is DataGridViewRadioButtonColumn) { //单行选择 if ((this.OwningColumn as DataGridViewRadioButtonColumn).SingleOn) { foreach (DataGridViewRow dr in this.DataGridView.Rows) { if (dr.Index != this.RowIndex) { (dr.Cells[this.ColumnIndex] as DataGridViewRadioButtonCell).Checked = false; } } } } if (OnRadioButtonClicked != null) { OnRadioButtonClicked(this, Checked); } if (this.DataGridView != null) { this.DataGridView.InvalidateCell(this); } } } } private bool _enabled = true; /// <summary> /// 是否可用 /// </summary> [Category("行为")] [Description("是否可用")] [DefaultValue(true)] [RefreshProperties(RefreshProperties.Repaint)] public bool Enabled { get { return _enabled; } set { if (_enabled != value) { _enabled = value; if (this.DataGridView != null) { this.DataGridView.InvalidateCell(this); } } } } #endregion /* /// <summary> /// 值 /// </summary> [Category("数据")] [Description("值")] [DefaultValue(true)] [RefreshProperties(RefreshProperties.Repaint)] public new string Value { get { return (Checked ? "1" : "0"); } set { if (value != null && value.Equals("1")) { Checked = true; } else { Checked = false; } } } */ private bool _isDefault = false; /// <summary> /// 是否是默认行 /// </summary> [Category("行为")] [Description("是否是默认行")] [DefaultValue(false)] [RefreshProperties(RefreshProperties.Repaint)] public bool IsDefault { get { return _isDefault; } set { if (_isDefault != value) { _isDefault = value; } } } private bool _display = true; /// <summary> /// 是否可见 /// </summary> [Category("外观")] [Description("是否可见")] [DefaultValue(true)] [RefreshProperties(RefreshProperties.Repaint)] public bool Display { get { return _display; } set { if (_display != value) { _display = value; if (this.DataGridView != null) { this.DataGridView.InvalidateCell(this); } } } } public event RadioButtonClickedHandler OnRadioButtonClicked; /// <summary> /// 是否已绑定事件 /// </summary> [DefaultValue(true)] [Browsable(false)] public bool EventIsNull { get { return OnRadioButtonClicked == null; } } #endregion public DataGridViewRadioButtonCell() { base.ReadOnly = true; } #region 绘制 protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates dataGridViewElementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { base.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, null, null, errorText, cellStyle, advancedBorderStyle, paintParts); if (Display) { Point p = new Point(); Size s = RadioButtonRenderer.GetGlyphSize(graphics, System.Windows.Forms.VisualStyles.RadioButtonState.UncheckedNormal); p.X = cellBounds.Location.X + (cellBounds.Width / 2) - (s.Width / 2); p.Y = cellBounds.Location.Y + (cellBounds.Height / 2) - (s.Height / 2); _cellLocation = cellBounds.Location; radioButtonLocation = p; radioButtonSize = s; if (Checked) { if (Enabled) { _cbState = System.Windows.Forms.VisualStyles.RadioButtonState.CheckedNormal; } else { _cbState = System.Windows.Forms.VisualStyles.RadioButtonState.CheckedDisabled; } } else { if (Enabled) { _cbState = System.Windows.Forms.VisualStyles.RadioButtonState.UncheckedNormal; } else { _cbState = System.Windows.Forms.VisualStyles.RadioButtonState.UncheckedDisabled; } } RadioButtonRenderer.DrawRadioButton(graphics, radioButtonLocation, _cbState); } } protected override void OnMouseClick(DataGridViewCellMouseEventArgs e) { //可以编辑 if (!(IsReadOnly == DataGridViewTriState.True) && Display && Enabled) { Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y); if (p.X >= radioButtonLocation.X && p.X <= radioButtonLocation.X + radioButtonSize.Width && p.Y >= radioButtonLocation.Y && p.Y <= radioButtonLocation.Y + radioButtonSize.Height) { Checked = !Checked; if (OnRadioButtonClicked != null) { OnRadioButtonClicked(this, Checked); } this.DataGridView.InvalidateCell(this); } } base.OnMouseClick(e); } protected override void OnKeyUp(KeyEventArgs e, int rowIndex) { base.OnKeyUp(e, rowIndex); if (!(IsReadOnly == DataGridViewTriState.True) && Display && Enabled) { if (e.KeyCode == Keys.Space) { Checked = !Checked; if (OnRadioButtonClicked != null) { OnRadioButtonClicked(this, Checked); this.DataGridView.InvalidateCell(this); } } } } #endregion } /// <summary> /// 状态变化事件 /// </summary> public delegate void RadioButtonClickedHandler(object sender, bool state); public class DataGridViewRadioButtonCellEventArgs : EventArgs { bool _bChecked; public DataGridViewRadioButtonCellEventArgs(bool bChecked) { _bChecked = bChecked; } public bool Checked { get { return _bChecked; } } }
列:

/// <summary> /// DataGridView单选列 /// </summary> public class DataGridViewRadioButtonColumn : DataGridViewColumn { #region Property private bool _isReadOnly = false; /// <summary> /// 是否只读 /// </summary> [Category("行为")] [Description("是否只读")] [DefaultValue(false)] [Browsable(true)] [RefreshProperties(RefreshProperties.Repaint)] public bool IsReadOnly { get { return _isReadOnly; } set { _isReadOnly = value; } } /// <summary> /// 是否只读 /// </summary> [Category("行为")] [Description("是否只读")] [DefaultValue(true)] [Browsable(false)] public new bool ReadOnly { get { return true; } set { base.ReadOnly = true; } } private bool _isSingleOn = true; /// <summary> /// 是否启用单行选中,单行模式,会自动控制其他行(不包括隐藏行)的选择 /// </summary> [Category("行为")] [Description("是否启用单行选中,单行模式,会自动控制其他行(不包括隐藏行)的选择")] [DefaultValue(true)] [Browsable(true)] public bool SingleOn { get { return _isSingleOn; } set { _isSingleOn = value; } } #endregion public DataGridViewRadioButtonColumn() { base.ReadOnly = true; base.CellTemplate = new DataGridViewRadioButtonCell(); } /// <summary> /// 保证属性编辑器里修改的值能保存 /// </summary> /// <returns></returns> public override object Clone() { DataGridViewRadioButtonColumn col = (DataGridViewRadioButtonColumn)base.Clone(); col.IsReadOnly = IsReadOnly; col.ReadOnly = true; col.SingleOn = SingleOn; return col; } }
参考:http://blog.163.com/szs1980@126/blog/static/478922032012124102158334/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了