イベントが必要なCheckedListBoxがありますafter新しい状態でCheckedItemsを使用できるように項目がチェックされます。
ItemCheckedはCheckedItemsが更新される前に起動されるため、そのままでは機能しません。
CheckedItemsが更新されたときに通知を受けるには、どのようなメソッドまたはイベントを使用できますか?
クリックされているアイテムの新しい状態も確認する場合は、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
...
}
関連するStackOverflowの投稿が多数あります... Branimir's ソリューションと同様に、さらに2つの簡単なものがあります。
ItemCheckの遅延実行 (また ここ ):
void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
this.BeginInvoke((MethodInvoker) (
() => Console.WriteLine(checkedListBox1.SelectedItems.Count)));
}
void checkedListBox1_MouseUp(object sender, MouseEventArgs e)
{
Console.WriteLine(checkedListBox1.SelectedItems.Count);
}
2番目のオプションは誤検知(つまり、頻繁に起動する)になるため、最初のオプションを選択します。
私はこれを試してみましたが、うまくいきました:
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();
}
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);
}
理想的ではありませんが、ItemCheck
イベントに渡される引数を使用してCheckedItemsを計算できます。これを見ると MSDNの例 で、新しく変更されたアイテムがチェックされているかチェックされていないかを判断できます。
アイテムがチェックされた後に起動する新しいイベントを作成することもできます。これにより、必要に応じて必要なものを正確に提供できます。
いくつかのテストの後、イベントItemCheckの後にイベントSelectedIndexChangedがトリガーされることがわかりました。プロパティCheckOnClickをTrueのままにします
最高のコーディング
これは動作しますが、どれだけエレガントかはわかりません!
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
ItemCheck
からの引数を保持したいが、モデルが変更された後に通知されると仮定すると、次のようになります。
CheckedListBox ctrl = new CheckedListBox();
ctrl.ItemCheck += (s, e) => BeginInvoke((MethodInvoker)(() => CheckedItemsChanged(s, e)));
CheckedItemsChanged
は次のとおりです。
private void CheckedItemsChanged(object sender, EventArgs e)
{
DoYourThing();
}
これが当てはまるかどうかはわかりませんが、チェックリストボックスを使用して結果をフィルタリングしたかったのです。したがって、ユーザーがアイテムをチェックしたりチェックを外したりすると、リストにアイテムの表示/非表示が必要になりました。
この投稿につながったいくつかの問題がありました。特別なことをせずにどうやってやったかを共有したかっただけです。
注: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
}
}
}
通常の動作では、1つのアイテムをチェックすると、イベントハンドラーが発生する前にアイテムのチェック状態が変更されます。ただし、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());}
この問題を解決するためにタイマーを使用します。 ItemCheckイベントを介してタイマーを有効にします。タイマーのティックイベントでアクションを実行します。
これは、アイテムがマウスクリックでチェックされるか、スペースバーを押すことでチェックされるかに関係なく機能します。チェックされた(またはチェックされていない)アイテムは常に選択されたアイテムであるという事実を利用します。
タイマーの間隔は1に設定できます。Tickイベントが発生するまでに、新しいCheckedステータスが設定されます。
このVB.NETコードは概念を示しています。使用できる多くのバリエーションがあります。タイマーの間隔を増やして、ユーザーがアクションを実行する前にいくつかのアイテムのチェック状態を変更できるようにすることができます。次に、Tickイベントで、List内のすべてのアイテムのシーケンシャルパスを作成するか、CheckedItemsコレクションを使用して適切なアクションを実行します。
そのため、最初にItemCheckイベントでタイマーを無効にします。無効にしてから有効にすると、間隔期間が再開します。
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