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

发布于 2024-09-18 09:13:31 字数 175 浏览 9 评论 0原文

我有一个 CheckedListBox,我希望在检查项目后发生一个事件,以便我可以在新状态下使用 CheckedItems。

由于 ItemChecked 在 CheckedItems 更新之前被触发,因此它无法开箱即用。

当 CheckedItems 更新时,我可以使用什么类型的方法或事件来收到通知?

I have a CheckedListBox where I want an event after an item is checked so that I can use CheckedItems with the new state.

Since ItemChecked is fired before CheckedItems is updated it won't work out of the box.

What kind of method or event can I use to be notified when the CheckedItems is updated?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

み格子的夏天 2024-09-25 09:13:31

如果您还检查所单击的项目的新状态,则可以使用 ItemCheck 事件。这在事件参数中可用,如 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
        ...
}

You can use the ItemCheck event, if you also check the new state of the item which is being clicked. This is available in the event args, as e.NewValue. If NewValue is checked, include the current item along with the collection proper in your logic:

    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)
        {
            ...
        }
    }

As another example, to determine if the collection will be empty after this item is (un-)checked:

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
        ...
}
暗藏城府 2024-09-25 09:13:31

StackOverflow 上有很多相关的帖子...以及 Branimir 的 解决方案,这里还有两个更简单的解决方案:

< a href="https://stackoverflow.com/a/4454594/188926">ItemCheck 延迟执行(也此处):

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

使用 MouseUp 事件

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

我更喜欢第一个选项,因为第二个选项会导致误报(即射击太频繁)。

There are lots of related StackOverflow posts on this... As well as Branimir's solution, here are two more simple ones:

Delayed execution on ItemCheck (also 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);
    }

I prefer the first option, as the second would result in false positives (i.e. firing too often).

百善笑为先 2024-09-25 09:13:31

我尝试了这个并且它有效:

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();        
}

I tried this and it worked:

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();        
}
夜唯美灬不弃 2024-09-25 09:13:31

派生自 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);
}

Derive from CheckedListBox and implement

/// <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);
}
海夕 2024-09-25 09:13:31

尽管并不理想,但您可以使用传递给 ItemCheck 事件的参数来计算 CheckedItems。如果您查看 MSDN 上的示例,您可以确定新更改的项目是否已选中或未选中,这使您处于合适的位置来处理这些项目。

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

Although not ideal, you can calculate the CheckedItems using the arguments that are passed through to the ItemCheck event. If you look at this example on MSDN, you can work out whether the newly changed item has been checked or unchecked, which leaves you in a suitable position to work with the items.

You could even create a new event that fires after an item is checked, which would give you exactly what you wanted if you wished.

凉薄对峙 2024-09-25 09:13:31

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

最佳编码

After some tests, I could see that the event SelectedIndexChanged is triggered after the event ItemCheck. Keep the property CheckOnClick True

Best coding

骑趴 2024-09-25 09:13:31

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

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

This works, not sure how elegant it is though!

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
情归归情 2024-09-25 09:13:31

我尝试了这个并且它有效:

    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);
        }
    }

通过列表的索引确定。

I tried this and it worked:

    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);
        }
    }

determine by index of the list.

椒妓 2024-09-25 09:13:31

不知道这是否适用,但我想使用清单框来过滤结果。因此,当用户选中和取消选中项目时,我希望列表显示\隐藏项目。

我遇到了一些问题,导致我写了这篇文章。只是想分享我是如何做到的,没有什么特别的。

” ,它可能仍然可以工作

注意:我有CheckOnClick = true,但如果没有我使用的事件是“SelectedIndexChanged”,

我使用的枚举是“.CheckedItems >”

这给出了我认为我们可以预期的结果。如此简化,归结为......

private void clb1_SelectedIndexChanged(object sender, EventArgs e)
{
   // This just spits out what is selected for testing
   foreach (string strChoice in clb1.CheckedItems)
   {
      listBox1.Items.Add(strChoice);
   }

   //Something more like what I'm actually doing
   foreach (object myRecord in myRecords)
   {
        if (clb1.CheckItems.Contains(myRecord["fieldname"])
        {
            //Display this record
        }
   }

}

Don't know if this applies but I wanted to use a checklistbox to filter results. So as the user checked and unchecked items I wanted the list to show\hide items.

I was having some issues which led me to this post. Just wanted to share how I did it without anything special.

Note: I have CheckOnClick = true but it would probably still work without

The event I use is "SelectedIndexChanged"

the enumeration I use is ".CheckedItems"

This give the results I think we may expect. So simplified it comes down to ....

private void clb1_SelectedIndexChanged(object sender, EventArgs e)
{
   // This just spits out what is selected for testing
   foreach (string strChoice in clb1.CheckedItems)
   {
      listBox1.Items.Add(strChoice);
   }

   //Something more like what I'm actually doing
   foreach (object myRecord in myRecords)
   {
        if (clb1.CheckItems.Contains(myRecord["fieldname"])
        {
            //Display this record
        }
   }

}
心房的律动 2024-09-25 09:13:31

假设您想保留 ItemCheck 中的参数,但在模型更改后收到通知,它应该如下所示:

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

其中 CheckedItemsChanged 可能是:

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

Assuming you want to preserve the arguments from ItemCheck but get notified after the model was changed it should look like that:

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

Where CheckedItemsChanged could be:

private void CheckedItemsChanged(object sender, EventArgs e)
{
    DoYourThing();
}
败给现实 2024-09-25 09:13:31

你的意思是checkboxlist,而不是checklistbox?如果是这样,相关事件将为 SelectedIndexChanged。

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

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

Do you mean checkboxlist, rather than checkedlistbox? If so, the the event concerned would be SelectedIndexChanged.

e.g. handler definition head in VB:

Protected Sub cblStores_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cblStores.SelectedIndexChanged
感情洁癖 2024-09-25 09:13:31

我决定不关心控件的感受,并处理该事件,就好像复选框更改确实已经完成一样。您所需要做的就是获取 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);
}

结果在功能上与假设的所需情况相同,其中事件仅在更改后触发。

I decided to just not care about the control's feelings, and handle the event as if the checkbox change indeed went through already. All you need to do is take the CheckedIndices list, and use the information in the ItemCheckEventArgs object to adjust it to the new state.

Then you can just loop over that list and retrieve the indicated items from the Items property of the control, and you have your CheckedItems list.

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);
}

The result is functionally identical to the hypothetical desired case where the event triggers only after the change.

梦幻的味道 2024-09-25 09:13:31

VB.NET 版本的 Dunc 的回答BeginInvoke 处理程序,以便检查该项目。

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

VB.NET version of Dunc's answer to BeginInvoke a handler so the item is checked.

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


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

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

  BeginInvoke(Sub() HandleItemCheck(e))

End Sub


Private Sub HandleItemCheck(e As ItemCheckEventArgs)

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

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

End Sub
苍景流年 2024-09-25 09:13:31

如果像我一样,您尝试使用“选择”作为一个指示器(用户选择的项目),并且用户想要更改刻度,那么我找到了一个偷偷摸摸的解决方案。

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

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

然后,为您的 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

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

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

,您将看到刻度闪烁,但可以调整计时器间隔,使其更适合您的情况。

If, like me, you were trying to use the Selection as one indicator (the item selected by the user), and the user wanting to changed the tick then I found a sneaky solution.

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

Create a timer on the page. For instance, mine is called tmrBan, and I have a CheckBoxList called clbFTI.

Then, create a Click Event for your CheckBoxList.

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

Then, create a Tick Event for your timer

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

You will see a flicker of the tick, but play around with the timer Interval to make this better for your case.

长伴 2024-09-25 09:13:31

我遇到了类似的问题:单击某个项目时,状态应从选中/未选中转换为相反。我在这里发布事件以及检查和更改:

CheckedListBox ChkLBox;
private void CheckedListBox_SelectedIndexChanged(object sender, EventArgs e)
{
    int SelectedIndex = ChkLBox.SelectedIndex; //
    var Item = ChkLBox.Items[SelectedIndex];

    bool IsChecked = (ChkLBox.GetItemChecked(ChkLBox.SelectedIndex));
    ChkLBox.SetItemChecked(ChkLBox.Items.IndexOf(Item), !IsChecked);
}

I ran into a similar issue: On a click of an item, the state should be converted from either checked/ non-checked to opposite. Here i post the event and the check and change:

CheckedListBox ChkLBox;
private void CheckedListBox_SelectedIndexChanged(object sender, EventArgs e)
{
    int SelectedIndex = ChkLBox.SelectedIndex; //
    var Item = ChkLBox.Items[SelectedIndex];

    bool IsChecked = (ChkLBox.GetItemChecked(ChkLBox.SelectedIndex));
    ChkLBox.SetItemChecked(ChkLBox.Items.IndexOf(Item), !IsChecked);
}
橘香 2024-09-25 09:13:31

当您搜索 VB dotnet (.NET) 解决方案时会出现此线程,因此我将把我想到的解决方案放在这里(调用)。

Private Sub CheckListBox1_ItemCheck(sender As Object, e As EventArgs) Handles checkListBox1.ItemCheck
    Me.BeginInvoke(New MethodInvoker(AddressOf CustomFunctionHere))
End Sub

Private Sub CustomFunctionHere()
    'Do something
End Sub

编辑:使用 Invoke 一段时间后,我意识到这对于我的项目来说并不是一个很好的解决方案。它可以工作,但是操作顺序会被打乱。相反,我创建了一种方法来使用 SelectedItems.Count 以及新旧选择值来计算“固定”计数,以确定是否应该从总数中添加或减去 1。

This thread comes up when you search for VB dotnet (.NET) solutions, so I'm just going to put the solution I came up with here (Invoke).

Private Sub CheckListBox1_ItemCheck(sender As Object, e As EventArgs) Handles checkListBox1.ItemCheck
    Me.BeginInvoke(New MethodInvoker(AddressOf CustomFunctionHere))
End Sub

Private Sub CustomFunctionHere()
    'Do something
End Sub

EDIT: After using Invoke for a while, I realized it is not a great solution for my project. It works, but the order of operations will be thrown off. Instead, I created a method to calculate the 'fixed' count using the SelectedItems.Count along with the old and new selection values to determine if I should add or subtract one from the total.

塔塔猫 2024-09-25 09:13:31

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

无论是通过单击鼠标还是按空格键检查该项目,这都有效。我们将利用这样一个事实:刚刚选中(或未选中)的项目始终是选定的项目。

计时器的间隔可以低至 1。当引发 Tick 事件时,将设置新的“已检查”状态。

此 VB.NET 代码展示了这个概念。您可以使用多种变体。您可能希望增加计时器的间隔,以允许用户在采取操作之前更改多个项目的检查状态。然后在 Tick 事件中,顺序传递列表中的所有项目或使用其 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

I use a Timer to solve this problem. Enable the timer via the ItemCheck event. Take action in the Timer's Tick event.

This works whether the item is checked via a mouse click or by pressing the Space-Bar. We'll take advantage of the fact that the item just checked (or un-checked) is always the Selected Item.

The Timer's Interval can be as low as 1. By the time the Tick event is raised, the new Checked status will be set.

This VB.NET code shows the concept. There are many variations you can employ. You may want to increase the Timer's Interval to allow the user to change the check status on several items before taking action. Then in the Tick event, make a sequential pass of all the Items in the List or use its CheckedItems collection to take appropriate action.

That's why we first disable the Timer in the ItemCheck event. Disable then Enable causes the Interval period to re-start.

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
长梦不多时 2024-09-25 09:13:31

在正常行为中,当我们检查一项时,该项目的检查状态将在引发事件处理程序之前发生变化。
但是 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());}

In normal behaviour, when we check one item, the item's check state will change before the event handler is raised.
But a CheckListBox has a different behaviour: The event handler is raised before the check state of the item changes and that makes it difficult to correct our jobs.

In my opinion, to solve this problem, we should defer the event handler.

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());}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文