C# · 12月 29, 2021

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

SelectedIndexChanged事件从我的应用程序从组合框中触发:

>用户选择不同的
组合框中的项目,或何时:
>我自己的代码更新组合
@R_180_2419@的SelectedItem反映出来
组合框现在正在显示
属性为不同的对象.

我对case1的SelectedIndexChanged事件感兴趣,所以我可以更新当前对象的属性.但是在第二种情况下,我不希望事件触发,因为对象的属性没有改变.

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

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

解决方法 我创建了一个我称为SuspendLatch的类.欢迎提供更好的名称,但它可以满足您的需要,您可以使用它: void Method(){ using (suspendLatch.GetToken()) { // Update selected index etc }}void list@R_180_2419@1_SelectedIndexChanged(object sender,EventArgs e){ if (suspendLatch.HasOutstandingTokens) { return; } // Do some work}

它不漂亮,但它的工作,不像注销事件或布尔标志,它支持嵌套操作有点像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); } }}