检查项目后会触发哪个CheckedListBox事件?

时间:2010-09-08 10:18:13

标签: c# winforms checkedlistbox

我有一个CheckedListBox,在项目被检查之后我需要一个事件,以便我可以使用具有新状态的CheckedItems。

由于在CheckedItems更新之前触发了ItemChecked,因此它不会开箱即用。

更新CheckedItems时,我可以使用哪种方法或事件来通知?

15 个答案:

答案 0 :(得分:74)

如果您还检查正在点击的项目的新状态,则可以使用ItemCheck事件。这在事件args中可用,e.NewValue。如果选中NewValue,请在逻辑中包含当前项目以及正确的集合:

    private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
    {                     
        List<string> checkedItems = new List<string>();
        foreach (var item in checkedListBox1.CheckedItems)
            checkedItems.Add(item.ToString());

        if (e.NewValue == CheckState.Checked)
            checkedItems.Add(checkedListBox1.Items[e.Index].ToString());
        else
            checkedItems.Remove(checkedListBox1.Items[e.Index].ToString());

        foreach (string item in checkedItems)
        {
            ...
        }
    }

作为另一个例子,确定在(未)检查此项目后该集合是否为空:

private void ListProjects_ItemCheck(object sender, ItemCheckEventArgs args)
{
    if (ListProjects.CheckedItems.Count == 1 && args.NewValue == CheckState.Unchecked)
        // The collection is about to be emptied: there's just one item checked, and it's being unchecked at this moment
        ...
    else
        // The collection will not be empty once this click is handled
        ...
}

答案 1 :(得分:28)

此处有很多相关的StackOverflow帖子......除Branimir's解决方案外,还有两个更简单的帖子:

Delayed execution on ItemCheck(也here):

    void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        this.BeginInvoke((MethodInvoker) (
            () => Console.WriteLine(checkedListBox1.SelectedItems.Count)));
    }

Using the MouseUp event

    void checkedListBox1_MouseUp(object sender, MouseEventArgs e)
    {
        Console.WriteLine(checkedListBox1.SelectedItems.Count);
    }

我更喜欢第一种选择,因为第二种选择会导致误报(即经常射击)。

答案 2 :(得分:20)

我试过这个并且有效:

private void clbOrg_ItemCheck(object sender, ItemCheckEventArgs e)
{
    CheckedListBox clb = (CheckedListBox)sender;
    // Switch off event handler
    clb.ItemCheck -= clbOrg_ItemCheck;
    clb.SetItemCheckState(e.Index, e.NewValue);
    // Switch on event handler
    clb.ItemCheck += clbOrg_ItemCheck;

    // Now you can go further
    CallExternalRoutine();        
}

答案 3 :(得分:9)

CheckedListBox派生并实施

/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.CheckedListBox.ItemCheck"/> event.
/// </summary>
/// <param name="ice">An <see cref="T:System.Windows.Forms.ItemCheckEventArgs"/> that contains the event data.
///                 </param>
protected override void OnItemCheck(ItemCheckEventArgs e)
{           
    base.OnItemCheck(e);

    EventHandler handler = AfterItemCheck;
    if (handler != null)
    {
        Delegate[] invocationList = AfterItemCheck.GetInvocationList();
        foreach (var receiver in invocationList)
        {
            AfterItemCheck -= (EventHandler) receiver;
        }

        SetItemCheckState(e.Index, e.NewValue);

        foreach (var receiver in invocationList)
        {
            AfterItemCheck += (EventHandler) receiver;
        }
    }
    OnAfterItemCheck(EventArgs.Empty);
}

public event EventHandler AfterItemCheck;

public void OnAfterItemCheck(EventArgs e)
{
    EventHandler handler = AfterItemCheck;
    if (handler != null)
        handler(this, e);
}

答案 4 :(得分:4)

虽然不理想,但您可以使用传递给ItemCheck事件的参数来计算CheckedItems。如果您查看此example on MSDN,您可以确定是否已选中或取消选中新更改的项目,这使您处于合适的位置以处理项目。

您甚至可以创建一个在检查项目后触发的新事件,如果您愿意,这将为您提供您想要的内容。

答案 5 :(得分:4)

经过一些测试,我可以看到事件ItemCheck后触发事件SelectedIndexChanged。保持属性CheckOnClick True

最佳编码

答案 6 :(得分:2)

这有效,但不确定它有多优雅!

Private Sub chkFilters_Changed(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkFilters.ItemCheck
    Static Updating As Boolean
    If Updating Then Exit Sub
    Updating = True

    Dim cmbBox As CheckedListBox = sender
    Dim Item As ItemCheckEventArgs = e

    If Item.NewValue = CheckState.Checked Then
        cmbBox.SetItemChecked(Item.Index, True)
    Else
        cmbBox.SetItemChecked(Item.Index, False)
    End If

    'Do something with the updated checked box
    Call LoadListData(Me, False)

    Updating = False
End Sub

答案 7 :(得分:1)

假设你想保留ItemCheck的参数,但在模型改变后得到通知,它应该是这样的:

CheckedListBox ctrl = new CheckedListBox();
ctrl.ItemCheck += (s, e) => BeginInvoke((MethodInvoker)(() => CheckedItemsChanged(s, e)));

CheckedItemsChanged可能是:

private void CheckedItemsChanged(object sender, EventArgs e)
{
    DoYourThing();
}

答案 8 :(得分:0)

我使用Timer来解决这个问题。通过ItemCheck事件启用计时器。在Timer的Tick事件中采取行动。

无论是通过鼠标单击还是按空格键检查项目,都可以使用此功能。我们将利用刚检查(或未检查)的项目始终是选定项目的事实。

定时器的间隔可以低至1.当Tick事件被提升时,将设置新的Checked状态。

这个VB.NET代码显示了这个概念。您可以使用许多变体。您可能希望增加计时器的间隔,以允许用户在采取措施之前更改多个项目的检查状态。然后在Tick事件中,对List中的所有Items进行顺序传递,或使用其CheckedItems集合采取适当的操作。

这就是为什么我们首先在ItemCheck事件中禁用Timer。禁用然后启用会导致间隔期重新启动。

Private Sub ckl_ItemCheck(ByVal sender As Object, _
                          ByVal e As System.Windows.Forms.ItemCheckEventArgs) _
    Handles ckl.ItemCheck

tmr.Enabled = False
tmr.Enabled = True

End Sub


Private Sub tmr_Tick(ByVal sender As System.Object, _
                     ByVal e As System.EventArgs) _
    Handles tmr.Tick

tmr.Enabled = False
Debug.Write(ckl.SelectedIndex)
Debug.Write(": ")
Debug.WriteLine(ckl.GetItemChecked(ckl.SelectedIndex).ToString)

End Sub

答案 9 :(得分:0)

在正常行为中,当我们检查一个项目时,项目的检查状态将在引发事件处理程序之前发生更改。 但是CheckListBox具有不同的行为:事件处理程序在项目的检查状态发生变化之前被引发,这使得我们很难纠正我们的工作。

在我看来,要解决这个问题,我们应该推迟事件处理程序。

private void _clb_ItemCheck(object sender, ItemCheckEventArgs e) {
 // Defer event handler execution
 Task.Factory.StartNew(() => {
     Thread.Sleep(1000);
     // Do your job at here
 })
 .ContinueWith(t => {
     // Then update GUI at here
 },TaskScheduler.FromCurrentSynchronizationContext());}

答案 10 :(得分:0)

我尝试了这个,并且奏效了:

    private List<bool> m_list = new List<bool>();
    private void Initialize()
    {
        for(int i=0; i < checkedListBox1.Items.Count; i++)
        {
            m_list.Add(false);
        }
    }

    private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        if (e.NewValue == CheckState.Checked)
        {
            m_list[e.Index] = true;
            checkedListBox1.SetItemChecked(e.Index, true);
        }
        else
        {
            m_list[e.Index] = false;
            checkedListBox1.SetItemChecked(e.Index, false);
        }
    }

通过列表的索引确定。

答案 11 :(得分:0)

您是指复选框列表,而不是复选框列表吗?如果是这样,则相关事件将为SelectedIndexChanged。

例如VB中的处理程序定义头:

Protected Sub cblStores_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cblStores.SelectedIndexChanged

答案 12 :(得分:0)

我决定不关心控件的感受,而是像处理复选框一样处理事件。您需要做的就是获取 CheckedIndices 列表,并使用 ItemCheckEventArgs 对象中的信息将其调整为新状态。

然后您只需遍历该列表并从控件的 Items 属性中检索指示的项目,您就拥有了 CheckedItems 列表。

private void CheckedList_ItemCheck(Object sender, ItemCheckEventArgs e)
{
    CheckedListBox checkedList = sender as CheckedListBox;
    if (checkedList == null)
        return;
    // Somehow this still returns the state before the check, so update it manually.
    List<Int32> checkedIndices = checkedList.CheckedIndices.Cast<Int32>().ToList();
    if (e.NewValue == CheckState.Unchecked)
        checkedIndices.Remove(e.Index);
    else if (e.NewValue == CheckState.Checked)
        checkedIndices.Add(e.Index);
    checkedIndices.Sort()
    Int32 checkedItemCount = checkedIndices.Length;
    Object[] checkedItems = new Object[checkedItemCount]
    for (Int32 i = 0; i < checkedItemCount; i++)
        checkedItems[i] = checkedList.Items[checkedIndices[i]];
    this.UpdateAfterCheckChange(checkedItems);
}

结果在功能上与假设的期望情况相同,即事件仅在更改后触发。

答案 13 :(得分:0)

VB.NET 版本的 Dunc's answerBeginInvoke 处理程序,以便检查项目。

Private Sub ChkListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles ChkListBox1.ItemCheck


  Debug.WriteLine($"checked item count {ChkListBox1.CheckedItems.Count}")

  Debug.WriteLine($"{ChkListBox1.Items(e.Index)} - {e.Index} - {e.NewValue}")

  BeginInvoke(Sub() HandleItemCheck(e))

End Sub


Private Sub HandleItemCheck(e As ItemCheckEventArgs)

  Debug.WriteLine($"handle item {ChkListBox1.Items(e.Index)} - {e.Index} - {e.NewValue}")

  Debug.WriteLine($"checked item count handle item - {ChkListBox1.CheckedItems.Count}")

End Sub

答案 14 :(得分:0)

如果像我一样,您试图将选择用作一个指标(用户选择的项目),而用户想要更改勾号,那么我找到了一个偷偷摸摸的解决方案。

Form variables
    Private IsTicked As Boolean = False
    Private ListIndex = -1

在页面上创建一个计时器。例如,我的名为 tmrBan,而我有一个名为 CheckBoxListclbFTI

然后,为您的 CheckBoxList 创建一个 Click 事件。

Private Sub clbFTI_Click(sender As Object, e As EventArgs) Handles lbFTI.MouseClick
    ListIndex = sender.SelectedIndex
    IsTicked = clbFTI.SelectedIndices.Contains(ListIndex)
    tmrBan.Interval = 10
    tmrBan.Enabled = True
End Sub

然后,为您的计时器创建一个 Tick 事件

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles tmrBan.Tick
    clbFTI.SetItemChecked(ListIndex, IsTicked)
End Sub

您会看到一个闪烁的滴答声,但可以调整计时器 Interval 以使其更适合您的情况。