为什么我的事件在未分配给任何控件时触发/从未分配给特定控件?

时间:2010-08-27 13:25:35

标签: c#

所以我有一些代码可以刷新表单上的控件以反映连接设备中的寄存器状态。在这段代码中,我使用MethodInvoker将进程执行到另一个线程,例如不锁定整个UI,这是一种异步刷新。无论如何,在这个MethodInvoker主体中,我首先“ - = new EventHandler(this._assignedEvent)”,禁用控件,根据设备寄存器状态更新其中一个属性,然后重新启用控件,并重新分配EventHandler。 / p>

在我目前的项目中,我已经多次复制了这个,大约90%的时间,这都有效。然而,对于大约三/四个控件我在特定形式上发生了这种情况:

  1. 删除控件x的事件
  2. 修改控件x
  3. 触发控件y的事件,永远不会将事件分配给x。
  4. 控制x的事件被解雇
  5. me = confused
  6. 这只发生在一些选择控件上,我想知道是否有一些我没有遵守的交叉线程执行规则或者其他东西......

    有问题的刷新代码如下所示:

    if (_prbsRxLockTime.Enabled)
                {
                    ParentDevice.Dongle.Read((RxSelect() == 0 ? _registers.PRBS_RX_2 : _registers.PRBS_RX_16).Offset.ToString("X"), ref result, 1);
                    bitMask = (ushort)(Bit.B0 | Bit.B1 | Bit.B2 | Bit.B3);
    
                    UpdateControlUsingMethod(new MethodInvoker(
                        () =>
                        {
                            this._prbsRxLockTime.SelectedIndexChanged -= new System.EventHandler(this._prbsRxLock_SelectedIndexChanged);
                            this._prbsRxLockTime.Enabled = false;
                            foreach (object i in _prbsRxLockTime.Items)
                            {
                                KeyValuePair<string, ushort> item = (KeyValuePair<string, ushort>)i;
                                if ((ushort.Parse(result, NumberStyles.HexNumber) & bitMask) == (ushort)(item.Value))
                                {
                                    _prbsRxLockTime.SelectedItem = i;
                                    break;
                                }
                            }
                            this._prbsRxLockTime.Enabled = true;
                            this._prbsRxLockTime.SelectedIndexChanged += new System.EventHandler(this._prbsRxLock_SelectedIndexChanged);
                        }
                    ));
                }
    

    修改_prbsRxLockTime.SelectedItem时触发的事件是:

    private void _prbsRxLOL_SelectedIndexChanged(object sender, EventArgs e)
        {
            ushort comboBoxData = (ushort)(((ComboBox)sender).SelectedValue);
            ushort bitMask = (ushort)(Bit.B0 | Bit.B1 | Bit.B2 | Bit.B3);
            string regAddress = string.Empty;
            string regData = comboBoxData.ToString("X").PadLeft(4, '0');
    
            switch (((ComboBox)sender).Name)
            {
                case "_prbsRxLOLTime":
                    regAddress = (RxSelect() == 0 ? _registers.PRBS_RX_5 : _registers.PRBS_RX_19).Offset.ToString("X");
                    break;
                case "_prbsRxLOLThresh":
                    regAddress = (RxSelect() == 0 ? _registers.PRBS_RX_6 : _registers.PRBS_RX_20).Offset.ToString("X");
                    break;
                default:
                    break;
            }
    
            ParentDevice.Dongle.Modify(regAddress, regData, 1, bitMask);
        }1.4.
    

1 个答案:

答案 0 :(得分:0)

我建议您阅读此Methodinvoker Invoke For a GUI App主题和此Safe,Simple Multithreading in WinForms文章,以检查您是否正确使用methodinvoker。

如果您解释第一个代码块何时以及由谁触发运行,建议您使用替代解决方案也可能会有所帮助。

在评论后编辑

抱歉,由于没有所有源代码,很难提出任何建议。它看起来像是一个事件订阅者留在代码中的某个地方,或者遇到与事件和多线程环境相关的问题,如Events and Deadlocks (See Comments Section)

另一个建议可能是替代解决方案,例如使用标志而不是控制具有一些副作用的事件订阅。您可以创建一个线程安全的属性,该属性指示SelectedIndexChanged过程不应处理的更新进度。

UpdateControlUsingMethod(new MethodInvoker(
    () =>
    {
        //this._prbsRxLockTime.SelectedIndexChanged -= new System.EventHandler(this._prbsRxLock_SelectedIndexChanged);
        this._prbRxLockTimeUpdatingByThread = true;

        //the code has been omitted here

        //this._prbsRxLockTime.SelectedIndexChanged += new System.EventHandler(this._prbsRxLock_SelectedIndexChanged);
        this._prbRxLockTimeUpdatingByThread = false;
    }
));

然后您可以在事件处理程序中检查该属性是否未运行标准过程。

private void _prbsRxLOL_SelectedIndexChanged(object sender, EventArgs e)
{
    if (this._prbRxLockTimeUpdatingByThread)
        return;

    //the code has been omitted here
}

希望得到这个帮助。