2010-09-08 358 views
65

我有一個CheckedListBox,我想要一個事件一個項目被選中,以便我可以使用CheckedItems與新狀態。檢查項目後,哪個CheckedListBox事件觸發?

由於ItemChecked是在CheckedItems更新之前觸發的,因此它將無法正常工作。

什麼樣的方法或事件可以用來在CheckedItems更新時得到通知?

回答

55

如果您還檢查正在單擊的項目的新狀態,則可以使用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()); 

     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 
     ... 
} 
+3

首先爲每個,我們可能需要添加一個條件..如果不是項目= checkedListBox1.Items [e.Index] .ToString()' – emaillenin 2012-05-15 10:54:51

+8

問題是,ItemCheck事件是f在檢查處理之前發生。您的解決方案將涉及保留自己的列表,基本上覆制標準代碼。 Dunc的第一個建議(對ItemCheck的延遲執行)是對phq問題最乾淨的回答,因爲它不需要任何額外的處理。 – 2014-08-29 04:48:09

4

雖然不理想,但您可以使用傳遞給ItemCheck事件的參數來計算CheckedItems。如果你看看這個example on MSDN,你可以計算出新更改的項目是否已被選中或未選中,這使您處於合適的位置來處理項目。

你甚至可以創建一個新的事件,在檢查一個項目後觸發,如果你願意,它會給你想要的東西。

+1

關於如何創建這個新事件,您有什麼具體的想法嗎?我怎麼知道CheckCheckItems在ItemChecke事件之後何時更新? – hultqvist 2010-09-09 12:09:04

22

有很多對本次關聯的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); 
    } 

我更喜歡第一個選項,因爲第二個選項會導致誤報(即觸發 太頻繁)。

+8

第二種方法也會錯過通過鍵盤選中或取消選中的項目。 – 2014-01-07 21:56:15

+1

BeginInvoke正是我所需要的,因爲我的事件實際上正在調用一個接口,它不知道它處理的是什麼樣的控制。被接受的答案只適用於邏輯可以在事件處理程序中執行的情況,或者直接從事件處理程序中調用的東西。對我來說情況並非如此。感謝這個真棒但簡單的解決方案。 – Jesse 2017-02-10 14:54:02

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 
15

我想這和它的工作:

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

這個! ...應該是正確的答案,這是最不幸的。這是一種荒謬的黑客行爲,因爲M $的某個人忘記了執行「ItemChecked」事件,並且從來沒有人說過它不存在。 – RLH 2014-09-26 16:26:30

+0

雖然它不是定義我認爲應該實現的錯誤,如果您同意考慮通過單擊+1支持此錯誤報告:https://connect.microsoft.com/VisualStudio/feedback/details/1759293 – Sebastian 2015-09-06 13:42:12

+0

@Sebastian - 不要在這裏要求解決。對此的任何「修復」都會破壞現有的解決方案。如果有兩個事件:ItemChecking,ItemChecked,那麼你可以使用後者。但是,如果只實現了一個('ItemCheck'),它正確地做了事情,即在* value被檢查之前觸發事件*,新值和索引作爲參數提供。無論誰想要「變更後」事件,他們都可以簡單地使用上述內容。如果向微軟建議,然後建議**新事件** ItemChecked,而不是改變現有的:請參閱[diimdeep的回答](http://stackoverflow.com/a/18487539/2392157) – miroxlav 2015-10-16 08:29:56

8

派生從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

一些測試後,我可以看到該事件的SelectedIndexChanged是在事件ItemCheck後觸發。保持房地產CheckOnClick真

最佳編碼

+0

你說得對,這是最簡單的方法。但它仍然像黑客一樣,因爲它沒有記錄和意外的行爲。任何微軟的新生可能會認爲:哦,爲什麼只有Checkstate更改時才啓用SelectedIndexChanged。我們來優化一下。並且Bang會代碼: – Rolf 2015-06-15 14:24:07

+0

此外,當您以編程方式更改檢查狀態時,SelectedIndexChanged不會觸發。 – Rolf 2015-06-15 14:35:32

-1

我用一個定時器來解決這個問題。通過ItemCheck事件啓用計時器。在定時器的滴答事件中採取行動。

無論項目是通過鼠標單擊還是通過按空格鍵進行檢查,這都可以工作。我們將利用這個事實,即剛剛選中的項目(或未選中)始終是選定項目。

定時器的間隔可以低至1.在引發滴答事件時,將設置新的檢查狀態。

這個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 
+0

Thak you for sharing。另一方面,也許您可​​以從其他答案中學到更好的解決方案。在這種情況下,它是錯誤的工具,因爲你實際上已經獲得了新的值作爲參數,所以你可以使用[這個答案](http://stackoverflow.com/a/17511730/2392157)關閉解決方案或[this one](http://stackoverflow.com/a/18487539/2392157)以獲得系統化解決方案。使用其中一種在線轉換工具將它們從C#轉換爲VB。 – miroxlav 2015-10-16 08:39:10

1

不知道這是否適用,但我想用checklistbox來過濾結果。因此,當用戶選中和取消選中項目時,我希望列表顯示\隱藏項目。

我遇到了一些問題,導致我到這篇文章。只是想分享我沒做過什麼特別的事情。

注:我有CheckOnClick =真,但它很可能仍然沒有

工作,我使用的事件是 「的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 
     } 
    } 

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

假設你想從ItemCheck保留的論據,但得到通知的模式改變了之後應該看起來像:

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

CheckedItemsChanged可能是:

private void CheckedItemsChanged(object sender, EventArgs e) 
{ 
    DoYourThing(); 
} 
相關問題