具有启用/禁用项目功能的自定义列表框控件






4.44/5 (7投票s)
具有启用/禁用项目功能的 C# 自定义 Listbox 控件
引言
我曾经遇到过一个案例,需要在 System.Windows.Forms.ListBox
控件中显示一些最终用户无法选择的项目,但仍然需要显示它们,因为最终用户期望看到它们。问题是 System.Windows.Forms.ListBox
不提供此功能,所以我决定创建自己的用户控件并分享它。
运行时控件
以下是控件在运行时的一些快照:[您可以下载示例项目并运行它].

禁用 Item3 [索引为 2] 后,我们将得到

现在 Item3 无法被选中,我们将对 Item5 [索引 4] 执行相同的操作,得到

启用 Item3 [索引 2] 将使该项目恢复到其默认状态

Using the Code
使用此控件非常简单。它的使用方式与内置的 ListBox
控件相同。
private Netdev.Windows.Forms.ListBox listBox1;
// Create a listbox object.
this.listBox1 = new Netdev.Windows.Forms.ListBox();
// Disable the item at the integer location index.
listBox1.DisableItem(index);
// Enable the item at the integer location index.
listBox1.EnableItem(index);
// We can also wire an event handler for Disabled items selection event.
// Whenever an end user tries to select a disabled item this event will be fired
this.listBox1.DisabledItemSelected += new System.EventHandler
<Netdev.Windows.Forms.IndexEventArgs>(this.listBox1_DisabledItemSelected);
代码描述
自定义的核心发生在 OnDrawItem
方法重写中。但是,只有当 DrawMode = DrawMode.OwnerDrawFixed;
(控件创建时的默认属性值)以及禁用的索引 [项目] 列表时,运行时才会调用此方法,如这个构造函数所示。
public ListBox()
{
DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
disabledIndices = new DisabledIndexCollection(this);
}
DisabledIndexCollection
:这是一个自定义集合,与保存 SelectedIndices
属性的集合相同。此集合跟踪列表中当前禁用的索引,这有助于 OnDrawItem
方法重写将这些项目显示为灰色项目,并防止最终用户选择它们。
以下是 OnDrawItem
方法的代码
protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
{
base.OnDrawItem(e);
if (DesignMode && Items.Count == 0)
{
if (e.Index == 0)
{
// Draw Control name as an item is design mode.
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
e.Graphics.DrawString(this.Name, e.Font, SystemBrushes.WindowText, e.Bounds);
}
return;
}
if (e.Index != ListBox.NoMatches)
{
object item = this.Items[e.Index];
// Get the text to display, this depends if the list is bound to data and
// DisplayMember, EnableFormating and FormatString are set.
string displayValue = GetItemText(item);
if (disabledIndices.Contains(e.Index))
{
e.Graphics.FillRectangle(SystemBrushes.InactiveBorder, e.Bounds);
e.Graphics.DrawString(displayValue, e.Font, SystemBrushes.GrayText, e.Bounds);
}
else
{
if (SelectionMode == System.Windows.Forms.SelectionMode.None)
{
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
e.Graphics.DrawString(displayValue, e.Font,
SystemBrushes.WindowText, e.Bounds);
}
else
{
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds);
e.DrawFocusRectangle();
e.Graphics.DrawString(displayValue, e.Font,
SystemBrushes.HighlightText, e.Bounds);
}
else
{
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
e.Graphics.DrawString(displayValue, e.Font,
SystemBrushes.WindowText, e.Bounds);
}
}
}
}
}
如果某个项目包含在 DisabledIndices
集合中,则将其显示为灰色。
最后,确保拦截 SelectedIndexChanged
事件,如果选定的项目被灰化,则通过重写 OnSelectedIndexChanged
方法来忽略它。
protected override void OnSelectedIndexChanged(EventArgs e)
{
// Retrieve new value of selected index.
int currentSelectedIndex = SelectedIndex;
List<int> selectedDisabledIndices = new List<int>();
for (int i = 0; i < SelectedIndices.Count; i++)
{
// unselect items that are already disabled.
if (disabledIndices.Contains(SelectedIndices[i]))
{
selectedDisabledIndices.Add(SelectedIndices[i]);
SelectedIndices.Remove(SelectedIndices[i]);
}
}
foreach (int index in selectedDisabledIndices)
{
// Fire DisabledItemSelected event for each
// disabled item that has been selected.
IndexEventArgs args = new IndexEventArgs(index);
OnDisabledItemSelected(this, args);
}
// if updated selected index is different than the
// original one then bubble up the event
if (currentSelectedIndex == SelectedIndex)
base.OnSelectedIndexChanged(e);
}
历史
- 更新版本 - 修复了与列表绑定到数据时项目显示值相关的问题,或者设置了
DisplayMember
、EnableFormating
和FormatString
时的问题