C# ListBox 變成 RadioListBox
C# ListBox 變成 RadioListBox
資料來源: https://www.codeproject.com/Articles/18526/RadioListBox-A-ListBox-with-Radio-Buttons-Winforms
using System.ComponentModel; using System.Drawing; using System.Windows.Forms.VisualStyles; namespace System.Windows.Forms { public class RadioListBox : ListBox { private StringFormat Align; private bool IsTransparent = false; private Brush BackBrush; // Allows the BackColor to be transparent public override Color BackColor { get { if (IsTransparent) return Color.Transparent; else return base.BackColor; } set { if (value == Color.Transparent) { IsTransparent = true; base.BackColor = (this.Parent == null) ? SystemColors.Window : this.Parent.BackColor; } else { IsTransparent = false; base.BackColor = value; } if (this.BackBrush != null) this.BackBrush.Dispose(); BackBrush = new SolidBrush(base.BackColor); Invalidate(); } } // Hides these properties in the designer [Browsable(false)] public override DrawMode DrawMode { get { return base.DrawMode; } set { if (value != DrawMode.OwnerDrawFixed) throw new Exception("Invalid value for DrawMode property"); else base.DrawMode = value; } } [Browsable(false)] public override SelectionMode SelectionMode { get { return base.SelectionMode; } set { if (value != SelectionMode.One) throw new Exception("Invalid value for SelectionMode property"); else base.SelectionMode = value; } } // Public constructor public RadioListBox() { this.DrawMode = DrawMode.OwnerDrawFixed; this.SelectionMode = SelectionMode.One; this.ItemHeight = this.FontHeight; this.Align = new StringFormat(StringFormat.GenericDefault); this.Align.LineAlignment = StringAlignment.Center; // Force transparent analisys this.BackColor = this.BackColor; } // Main paiting method protected override void OnDrawItem(DrawItemEventArgs e) { int maxItem = this.Items.Count - 1; if (e.Index < 0 || e.Index > maxItem) { // Erase all background if control has no items e.Graphics.FillRectangle(BackBrush, this.ClientRectangle); return; } int size = e.Font.Height; // button size depends on font height, not on item height // Calculate bounds for background, if last item paint up to bottom of control Rectangle backRect = e.Bounds; if (e.Index == maxItem) backRect.Height = this.ClientRectangle.Top + this.ClientRectangle.Height - e.Bounds.Top; e.Graphics.FillRectangle(BackBrush, backRect); // Determines text color/brush Brush textBrush; bool isChecked = (e.State & DrawItemState.Selected) == DrawItemState.Selected; RadioButtonState state = isChecked ? RadioButtonState.CheckedNormal : RadioButtonState.UncheckedNormal; if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled) { textBrush = SystemBrushes.GrayText; state = isChecked ? RadioButtonState.CheckedDisabled : RadioButtonState.UncheckedDisabled; } else if ((e.State & DrawItemState.Grayed) == DrawItemState.Grayed) { textBrush = SystemBrushes.GrayText; state = isChecked ? RadioButtonState.CheckedDisabled : RadioButtonState.UncheckedDisabled; } else { textBrush = SystemBrushes.FromSystemColor(this.ForeColor); } // Determines bounds for text and radio button Size glyphSize = RadioButtonRenderer.GetGlyphSize(e.Graphics, state); Point glyphLocation = e.Bounds.Location; glyphLocation.Y += (e.Bounds.Height - glyphSize.Height) / 2; Rectangle bounds = new Rectangle(e.Bounds.X + glyphSize.Width, e.Bounds.Y, e.Bounds.Width - glyphSize.Width, e.Bounds.Height); // Draws the radio button RadioButtonRenderer.DrawRadioButton(e.Graphics, glyphLocation, state); // Draws the text if (!string.IsNullOrEmpty(DisplayMember)) // Bound Datatable? Then show the column written in Displaymember e.Graphics.DrawString(((System.Data.DataRowView)this.Items[e.Index])[this.DisplayMember].ToString(), e.Font, textBrush, bounds, this.Align); else e.Graphics.DrawString(this.Items[e.Index].ToString(), e.Font, textBrush, bounds, this.Align); // If the ListBox has focus, draw a focus rectangle around the selected item. e.DrawFocusRectangle(); } // Prevent background erasing protected override void DefWndProc(ref Message m) { if (m.Msg == 0x0014) // WM_ERASEBKGND { m.Result = (IntPtr)1; // avoid default background erasing return; } base.DefWndProc(ref m); } // Other event handlers protected override void OnHandleCreated(EventArgs e) { if (this.FontHeight > this.ItemHeight) this.ItemHeight = this.FontHeight; base.OnHandleCreated(e); } protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); if (this.FontHeight > this.ItemHeight) this.ItemHeight = this.FontHeight; Update(); } protected override void OnParentChanged(EventArgs e) { // Force to change backcolor this.BackColor = this.BackColor; } protected override void OnParentBackColorChanged(EventArgs e) { // Force to change backcolor this.BackColor = this.BackColor; } } }