为什么具有Indeterminate状态的Checkbox被更改为Unchecked状态?

时间:2014-09-11 20:46:30

标签: c# winforms

我有两个CheckBoxListprimaryAntennassecondaryAntennas 检查索引为X的主天线时,应禁用索引为X的辅助天线(即检查主天线#1,禁用辅助天线#1)。反向,应该以同样的方式工作。通过将复选框设置为CheckState.Indeterminate

来禁用

example1
我很快发现,您可以点击Indeterminate复选框,其状态将设置为CheckState.Unchecked
example2
为了解决这个问题,我在点击处理程序中添加了一个检查,它将复选框重置为不确定状态:

if (e.CurrentValue == CheckState.Indeterminate)
{
   this.primaryAntennas.ItemCheck -= this.primaryAntennas_ItemCheck;
   // set it back to indeterminate state 
   this.primaryAntennas.SetItemCheckState(e.Index, CheckState.Indeterminate);
   this.primaryAntennas.ItemCheck += this.primaryAntennas_ItemCheck;
   return;
}

仍然,点击处理程序完成后,取消选中复选框。 这里是点击处理程序的完整代码:
(您可能会注意到我显式未分配事件处理程序,因为调用自身可以创建一个无限循环。此外,事件处理程序可以相互调用,创建另一种无限循环的可能性)

private void primaryAntennas_ItemCheck(object sender, ItemCheckEventArgs e)
{
    //check if checkbox is indeterminate
    if (e.CurrentValue == CheckState.Indeterminate)
    {
        this.primaryAntennas.ItemCheck -= this.primaryAntennas_ItemCheck;
        // set it back to indeterminate state 
        this.primaryAntennas.SetItemCheckState(e.Index, CheckState.Indeterminate);
        this.primaryAntennas.ItemCheck += this.primaryAntennas_ItemCheck;
        return;
    }

    // if the item was checked
    // disable the secondary antenna with the same index
    if (e.NewValue == CheckState.Checked)
    {
        // disable the secondary antenna
        this.secondaryAntennas.ItemCheck -= this.secondaryAntennas_ItemCheck;
        secondaryAntennas.SetItemCheckState(e.Index, CheckState.Indeterminate);
        this.secondaryAntennas.ItemCheck += this.secondaryAntennas_ItemCheck;
        return;
    }
    // if the item was unchecked
    // disable the primary antenna with the same index
    if (e.NewValue == CheckState.Unchecked)
    {
        // check to make sure it does not belong to other portal
        if (_myConfig.secondaryAntessasUsed[e.Index] == -1)
        {
            // disable even
            this.secondaryAntennas.ItemCheck -= this.secondaryAntennas_ItemCheck;
            // uncheck the antenna
            secondaryAntennas.SetItemCheckState(e.Index, CheckState.Unchecked);
            this.secondaryAntennas.ItemCheck += this.secondaryAntennas_ItemCheck;
            return;
        }
    } 
}// end of primaryAntennas_ItemCheck()

4 个答案:

答案 0 :(得分:4)

这是一种伪造复选框“禁用”状态的新方法。不太确定你会为你的用户提供帮助,更容易让它独占,检查一个取消选中另一个。但是,从技术上讲,只需强制e.NewValue状态,​​这样点击就没有任何效果了。

为两个CheckedListBox提供相同的事件处理程序:

    private bool updatingChecks;

    private void checkedListBoxes_ItemCheck(object sender, ItemCheckEventArgs e) {
        if (updatingChecks) return;
        updatingChecks = true;
        var otherBox = sender == checkedListBox1 ? checkedListBox2 : checkedListBox1;
        if (otherBox.GetItemCheckState(e.Index) == CheckState.Checked) e.NewValue = e.CurrentValue;
        else if (e.NewValue == CheckState.Checked) otherBox.SetItemCheckState(e.Index, CheckState.Indeterminate);
        else if (e.NewValue == CheckState.Unchecked) otherBox.SetItemChecked(e.Index, false);
        updatingChecks = false;
    }

对我来说更有意义的版本,它不会忽略用户的点击:

    private void checkedListBoxes_ItemCheck(object sender, ItemCheckEventArgs e) {
        var otherBox = sender == checkedListBox1 ? checkedListBox2 : checkedListBox1;
        if (e.NewValue == CheckState.Checked) otherBox.SetItemChecked(e.Index, false);
    }

请确保您实际上并不打算实施RadioButtons。当然看起来像。

答案 1 :(得分:1)

在事件处理程序中使用SetItemCheckState将不起作用。相反,您需要在事件参数上设置NewValue属性。

if (e.CurrentValue == CheckState.Indeterminate)
{
   e.NewValue = CheckState.Indeterminate;
   return;
}

这另外修复了你的递归问题,因为它在现有事件中起作用而不是触发新事件。

答案 2 :(得分:0)

这可能会强制用户取消选中列表框选项

private void checkedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        if (e.CurrentValue == CheckState.Indeterminate && e.NewValue !=  CheckState.Indeterminate)
        {
            e.NewValue = CheckState.Indeterminate;
            checkedListBox.SetItemCheckState(e.Index, CheckState.Indeterminate);
            return;
        }
    }

答案 3 :(得分:-1)

一种解决方案是对每个复选框使用ItemChecked事件来设置其他复选框项的值。为了使这项工作,我们需要跟踪用户点击一个方框是否触发了ItemChecked事件,还是通过其他ItemChecked事件中的代码来跟踪。

此外,由于两个ItemCheck事件中的代码几乎相同,我为它创建了一个单独的方法,它接收“其他”复选框(要更改的复选框)以及事件参数。

我将如何做到这一点:

private bool userTriggered = true; // True means the user is triggering the event

private void primaryAntennas_ItemCheck(object sender, ItemCheckEventArgs e)
{
    // If triggered by other ItemCheck method, let the change take place...
    if (!userTriggered) return;

    // Otherwise we process it and update the other CheckedListBox
    processItemCheckEvent(this.secondaryAntennas, e);
}

private void secondaryAntennas_ItemCheck(object sender, ItemCheckEventArgs e)
{
    // If triggered by other ItemCheck method, let the change take place...
    if (!userTriggered) return;

    // Otherwise we process it and update the other CheckedListBox
    processItemCheckEvent(this.primaryAntennas, e);
}

private void processItemCheckEvent(CheckedListBox otherCheckedListBox, ItemCheckEventArgs e)
{
    // Ignore user changes if we're 'disabled'
    if (e.CurrentValue == CheckState.Indeterminate)
    {
        e.NewValue = CheckState.Indeterminate;
    }
    // Otherwise change the other check box
    else
    {
        // Now we're manipulating the other checkedListBox, 
        // so set userTriggered to false
        userTriggered = false;
        if (e.NewValue == CheckState.Checked)
        {
            otherCheckedListBox.SetItemCheckState(e.Index, CheckState.Indeterminate);
        }
        else
        {
            otherCheckedListBox.SetItemCheckState(e.Index, CheckState.Unchecked);
        }
        // And set it back again now
        userTriggered = true;
    }
}