如何在已选中的复选框列表框中禁用复选框?

23

我在一个CheckedListBox中有一些项目,我想要禁用它里面的第一个项目的CheckBox
即我想要禁用CheckedListBox中的第一项,因为我想要通过视觉告诉用户该选项不可用。

11个回答

19
尽管这篇文章相当老,但最后添加的答案是在今年4月份提交的,希望这能帮助到某些人。 我想要类似的东西:一个检查过的列表框,像许多安装程序一样,提供一个选项列表,其中一些功能是必需的,因此既被选中又被禁用。
感谢这篇文章(可以使用DrawItem事件处理程序与CheckedListBox吗?)我设法做到了这一点,子类化了一个CheckedListBox控件。 正如链接帖子中的OP所述,在CheckedListBox控件中,OnDrawItem事件永远不会触发,因此需要子类化。 这非常基础,但它起作用。 这就像这样(上面的CheckBox是为了比较):
注:禁用的项目真正被禁用了:我无法看出单击它会有任何影响。
这是代码:
public class CheckedListBoxDisabledItems : CheckedListBox {
    private List<string> _checkedAndDisabledItems = new List<string>();
    private List<int> _checkedAndDisabledIndexes = new List<int>();

    public void CheckAndDisable(string item) {
        _checkedAndDisabledItems.Add(item);
        this.Refresh();
    }

    public void CheckAndDisable(int index) {
        _checkedAndDisabledIndexes.Add(index);
        this.Refresh();
    }

    protected override void OnDrawItem(DrawItemEventArgs e) {
        string s = Items[e.Index].ToString();

        if (_checkedAndDisabledItems.Contains(s) || _checkedAndDisabledIndexes.Contains(e.Index)) {
            System.Windows.Forms.VisualStyles.CheckBoxState state = System.Windows.Forms.VisualStyles.CheckBoxState.CheckedDisabled;
            Size glyphSize = CheckBoxRenderer.GetGlyphSize(e.Graphics, state);
            CheckBoxRenderer.DrawCheckBox(
                e.Graphics,
                new Point(e.Bounds.X + 1, e.Bounds.Y + 1), // add one pixel to align the check gliph properly
                new Rectangle(
                    new Point(e.Bounds.X + glyphSize.Width + 3, e.Bounds.Y), // add three pixels to align text properly
                    new Size(e.Bounds.Width - glyphSize.Width, e.Bounds.Height)),
                s,
                this.Font,
                TextFormatFlags.Left, // text is centered by default
                false,
                state); 
        }
        else {
            base.OnDrawItem(e);
        }
    }

    public void ClearDisabledItems() {
        _checkedAndDisabledIndexes.Clear();
        _checkedAndDisabledItems.Clear();
        this.Refresh();
    }
}

像这样使用:

checkedListBox.Items.Add("Larry");
checkedListBox.Items.Add("Curly");
checkedListBox.Items.Add("Moe");

// these lines are equivalent
checkedListBox.CheckAndDisable("Larry");
checkedListBox.CheckAndDisable(0);

希望这能帮助到某些人。


谢谢,它像魔法一样奏效! 不过,在查看包含您定义的自定义控件的表单预览时,它会生成一个问题:它会生成一个无效参数异常:“'0'的值对于'索引'无效”。您应该在OnDrawItem()方法的开头添加类似以下的内容: if (Items.Count < e.Index + 1) { return; } - Alessandro Martinelli

19

以上两个部分回答的结合对我非常有效。 使用以下方法将您的项目添加到列表中:

myCheckedListBox.Items.Add(myItem, myState);

对于应该被禁用的项目,myState为CheckState.Indeterminate。然后添加事件处理程序以防止更改这些项目:

myCheckedListBox.ItemCheck += (s, e) => { if (e.CurrentValue == CheckState.Indeterminate) e.NewValue = CheckState.Indeterminate; };

这并不允许你像正常情况下一样在此列表中使用“未定”(Indeterminate),但它确实提供了一个非常类似于禁用项目的外观,并且它提供了正确的行为!


刚刚尝试了同样的事情,需要注意的是,使用此事件处理程序时,您无法在将复选框“禁用”后以编程方式重新启用它--ItemCheck事件会触发,看到现有的不确定状态并覆盖您。在大多数情况下,您需要进行额外的布尔检查,以确定状态更改是由用户发起还是由程序发起的。当然,如何保护该布尔值免受竞态条件的影响是读者的练习... - jimbobmcgee

12

禁用项目并不是一个好主意,因为用户没有良好的反馈来告知点击复选框没有任何效果。您不能使用自定义绘图来使其明显。最好的做法是简单地省略该项目。

不过,您可以轻松地通过ItemCheck事件打败用户:

    private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
        if (e.Index == 0) e.NewValue = e.CurrentValue;
    }

3
谢谢,但我希望您能通过视觉方式告诉用户该选项不可用。 - Subodh Bansal
1
“不能使用自定义绘图”--这不是真的,但有些困难。以文本形式自定义绘制为禁用状态会更容易,并且使用此处提供的禁用代码。 - Jon Seigel
1
重新实现自定义绘图与使用CheckedListBox的初衷相违背,还不如使用ListBox。正如所述,让选项无法使用的简单方法是将其从Items集合中移除。 - Hans Passant
很棒的答案。谢谢。 - Ashkan Mobayen Khiabani
与我在https://dev59.com/Wm855IYBdhLWcg3wZzXf#FAMZoYgBc1ULPQZFHf_9中的评论一样,ItemCheck事件将拦截任何尝试更改复选框状态的操作,包括“重新启用”复选框的尝试。需要进行其他检查以克服这个问题。 - jimbobmcgee
嗯,不,我发布的那个ItemCheck事件处理程序绝对可以防止第一个项目的检查状态被更改。试试看吧。 - Hans Passant

11

要禁用任何特定项目,请使用以下内容:

checkedListBox1.SetItemCheckState(0, CheckState.Indeterminate);

SetItemCheckState接受项目的索引和CheckState枚举类型,Indeterminate用于显示阴影外观。


2
这会显示为灰色外观,但不会阻止用户检查该项(我猜可以通过实现监听器来完成)。 - personne3000

5

虽然已经过了一段时间,但我在寻找列表框时发现了这个问题,并想将其添加到讨论中。

如果您有一个列表框,并希望禁用所有复选框以使其无法点击,但不禁用控件,以便用户仍然可以滚动等操作,则可以执行以下操作:

listbox.SelectionMode = SelectionMode.None

3

这种方式无法使用CheckedListBox。 CheckedListBox.Items 是一个字符串集合,因此它们不能被“禁用”。

以下是一些可能有帮助的解决方案讨论:这里这里


2
这对我有效:
checkedListBox1.SelectionMode = SelectionMode.None;

这意味着没有任何项目可以被选择。

无:无法选择任何项目。

更多信息,请查看此处:SelectionMode 枚举


1
解决方案是使用事件ItemChecking:
_myCheckedListBox.ItemChecking += (s, e) => e.Cancel = true;

这将取消每个项目上的所有检查,但您始终可以通过测试当前的.SelectedItem来进行更精细的解决方案。


0

尝试以下代码:

Private Sub CheckedListBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles CheckedListBox1.MouseUp
        If (Condition) Then
         Me.CheckedListBox1.SelectedIndex = -1
        End If
End Sub

0

我认为另一种解决方案是使用 Telerik 组件。

RadListControl 可以提供这个选项:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接