区分用户交互和我自己的代码引发的事件

9 c# events combobox winforms

在以下情况SelectedIndexChanged下,从组合框中在我的应用程序中触发该事件:

  1. 用户在组合框中选择不同的项目,或者在以下情况下:
  2. 我自己的代码更新了组合框,SelectedItem以反映组合框现在显示不同对象的属性.

SelectedIndexChanged对案例1 的事件感兴趣,以便我可以更新当前对象的属性.但在案例2中,我不希望事件触发,因为对象的属性没有改变.

一个例子可能有帮助.让我们考虑一下,我有一个包含人员列表的列表框,我有一个组合框,表示列表中当前所选人员的国籍.如果当前在列表中选择了Fred,则可能发生情况1,并且我使用组合框将他的国籍从英语更改为威尔士语.如果我在列表中选择苏格兰人Bob,则可能发生案例2.在这里,我的列表更新事件处理程序代码看到Bob现在被选中,并更新组合框,以便苏格兰语现在是所选项目.这导致组合框的SelectedIndexChanged事件被触发以将Bob的国籍设置为苏格兰语,尽管它已经是苏格兰人.

如何在SelectedItem不导致SelectedIndexChanged事件触发的情况下更新我的组合框的属性?一种方法是取消注册事件处理程序,设置SelectedItem,然后重新注册事件处理程序,但这似乎很乏味且容易出错.肯定有更好的办法.

Nei*_*ell 7

我创建了一个叫做的课程SuspendLatch.欢迎提供更好名称的优惠,但它可以满足您的需求,您可以像这样使用它:

void Method()
{
    using (suspendLatch.GetToken())
    {
        // Update selected index etc
    }
}

void listbox1_SelectedIndexChanged(object sender, EventArgs e)
{
    if (suspendLatch.HasOutstandingTokens)
    {
        return;
    }

    // Do some work
}
Run Code Online (Sandbox Code Playgroud)

它不漂亮,但确实有效,与注销事件或布尔标志不同,它支持嵌套操作,有点像TransactionScope.你继续从锁存器获取令牌,只有当最后一个令牌被丢弃时才会HasOutstandingTokens返回false.很好,很安全.虽然不是线程安全的......

这是SuspendLatch的代码:

public class SuspendLatch
{
    private IDictionary<Guid, SuspendLatchToken> tokens = new Dictionary<Guid, SuspendLatchToken>();

    public SuspendLatchToken GetToken()
    {
        SuspendLatchToken token = new SuspendLatchToken(this);
        tokens.Add(token.Key, token);
        return token;
    }

    public bool HasOutstandingTokens
    {
        get { return tokens.Count > 0; }
    }

    public void CancelToken(SuspendLatchToken token)
    {
        tokens.Remove(token.Key);
    }

    public class SuspendLatchToken : IDisposable
    {
        private bool disposed = false;
        private Guid key = Guid.NewGuid();
        private SuspendLatch parent;

        internal SuspendLatchToken(SuspendLatch parent)
        {
            this.parent = parent;
        }

        public Guid Key
        {
            get { return this.key; }
        }

        public override bool Equals(object obj)
        {
            SuspendLatchToken other = obj as SuspendLatchToken;

            if (other != null)
            {
                return Key.Equals(other.Key);
            }
            else
            {
                return false;
            }
        }

        public override int GetHashCode()
        {
            return Key.GetHashCode();
        }

        public override string ToString()
        {
            return Key.ToString();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // Dispose managed resources.
                    parent.CancelToken(this);
                }

                // There are no unmanaged resources to release, but
                // if we add them, they need to be released here.
            }
            disposed = true;

            // If it is available, make the call to the
            // base class's Dispose(Boolean) method
            //base.Dispose(disposing);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)