![]() |
Desktop Development »
Combo & List Boxes »
General
Intermediate
License: The Code Project Open License (CPOL)
RadioListBox: A ListBox with Radio Buttons (Winforms version)By Jaime OlivaresHow to implement an owner-drawn ListBox with radio buttons instead of standard selection highlight |
C# 2.0.NET 2.0, WinXP, VistaVS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This is the .NET version of my previous MFC article, CRadioListBox: A ListBox with Radio Buttons. A couple of years ago, I discussed in a Visual C++ forum about a member's request to implement a custom ListBox control similar to MFC's CCheckListBox, but with radio buttons. Initially it appeared to be trivial, since the ListBox control's unique selection version complies with the requirements, but I have concluded that this control has some advantages:
To implement RadioListBox into your project, you just need to do a few steps:
RadioListBox object into your form. ListBox. ListBox, transparent BackColor property is allowed. That's all! Now you can use the radio button collection as a regular ListBox. You can add items with the Items.Add() method and query for user selection with the SelectedIndex property.
Some .NET controls accept a transparent color as a BackColor property, but ListBox is not one of them. So, transparency requires lots of non-managed tricks. However, transparency is a key feature needed for this control to be useful. It allows the control to acquire a real radio button look and feel, as you can see in the screenshot above. I decided to stay in the managed world by providing fake transparency to the control by overriding the BackColor property to accept it, and saving its own background color brush. When setting the background color to transparent, the control will mimic the parent form or control, even if the form has a non-standard background color.
The RadioListBox class is derived from Windows Forms' ListBox class with the owner-draw feature. The resumed class definition is the following:
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; // Handles the transparent state
private Brush BackBrush; // Manages its own background brush
// Allows the BackColor to be transparent
public override Color BackColor ...
// Hides these properties in the designer
[Browsable(false)]
public override DrawMode DrawMode ...
[Browsable(false)]
public override SelectionMode SelectionMode ...
// Public constructor
public RadioListBox() ...
// Main painting method
protected override void OnDrawItem(DrawItemEventArgs e) ...
// Prevent background erasing
protected override void DefWndProc(ref Message m) ...
// Other event handlers
protected override void OnHandleCreated(EventArgs e) ...
protected override void OnFontChanged(EventArgs e) ...
protected override void OnParentChanged(EventArgs e) ...
protected override void OnParentBackColorChanged(EventArgs e) ...
}
}
The core enhancement is at the OnDrawItem() method. The method does not highlight the selected item as in a standard ListBox control, but draws a radio button instead. It also manages the focus state to draw the focus rectangle properly and the background color according to the transparency attribute. Here is the C# source code:
// Main painting 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
// Bound Datatable? Then show the column written in Displaymember
if (!string.IsNullOrEmpty(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();
}
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 3 Sep 2008 Editor: Sean Ewington |
Copyright 2007 by Jaime Olivares Everything else Copyright © CodeProject, 1999-2009 Web19 | Advertise on the Code Project |