排队ObservableCollection更新

时间:2011-10-17 10:34:19

标签: c# message-queue observablecollection state-machine

我正在编写一个TAPI应用程序,该应用程序使用状态模式来处理TK可以处于的不同状态。传入和传出呼叫通过ObservableCollection(呼叫日志)中的ListView进行记录。将呼叫数据与存储在SQL-Server数据库中的联系人进行比较,以确定可能的匹配。然后,该信息用于更新呼叫日志。所有这些当然是实时的,并且全部由FSM(有限状态机)的不同状态控制。

为区分呼叫,我使用呼叫ID(由TAPI提供)。当电话响铃或我开始呼叫时,包括其呼叫ID的新记录被添加到呼叫日志中,并且在客户数据库中搜索该号码并且相应地更新日志中的某些数据。当继续通过不同的呼叫状态时,应用程序动态更新日志(即,更改可视地显示特定呼叫状态的图标等)。

ObservableCollection的正确更新让我感到头痛,因为它们需要按特定顺序发生。例如,当接收呼叫时,关联状态将在ObservableCollection中创建新条目。当状态改变时,新状态可能会尝试更新集合,即使天气不明确,已经添加了要更改的条目。状态碰巧切换得非常快,显然比更新集合更快。

某种消息队列是否可能/良好的解决方案?如果是这样,那么如何实现这样的消息队列 - 在状态机或ObservableCollection的上下文中。我不是在寻找完整的解决方案,但任何我无法通过google或stackoverflow轻松找到的信息都将受到赞赏。

编辑:大大改写了这个问题。

编辑:我为问题添加了自己的解决方案,但会等待,看看是否有人可能有更好的想法。

2 个答案:

答案 0 :(得分:1)

您是否检查过FirstOrDefault的结果是否为null?如果集合中不存在给定id的元素,则会发生这种情况。

例如:

var element = this.FirstOrDefault(p => p.ID == id);
if (element != null) {
    // Do something with element.Number.
}

或者您可以致电First并查看是否获得InvalidOperationException

---编辑---

我从您的评论中看到您似乎同时从多个线程访问相同的ObservableCollection。如果是这种情况,则需要通过锁定来保护共享数据结构。一个线程完全有可能在另一个线程正在搜索它时开始插入新元素,从而导致各种未定义的行为。根据{{​​3}}:

“不保证所有实例成员都是线程安全的。”

至于调试,你可以“冻结”其他线程,这样你就可以只关注感兴趣的线程,而不会过度“跳跃”。请参阅“线程”面板,右键单击菜单,“冻结和解冻”选项。

答案 1 :(得分:1)

更新ObservableCollection是一个漫长的过程,至少与接收和处理TAPI事件相比。这可能导致竞争条件,其中必须编辑呼叫条目的呼叫状态无法找到条目,因为它获得了在实际必须添加呼叫的呼叫状态之前写入/更新集合的锁定。此外,不按正确顺序处理TAPI事件会破坏状态机。

我决定实施简化的Command Pattern。用于触发性能繁重的状态事务的TAPI-Events被添加到线程安全,非阻塞和可观察的命令队列中。当命令进入队列时,队列类开始在新线程中“执行”(和出列)命令,即它在有限状态机中触发正确的调用状态,直到队列中没有命令为止。如果有一个已经运行的出列线程没有创建新线程(多线程会再次导致竞争条件),并且队列类阻止了重入,以确保在任何时候只执行一个命令。

基本上:所有TAPI事件(调用者)都按其发生的顺序添加到队列(客户端)中,尽可能快。然后,队列将TAPI信息中继到执行业务逻辑的有限状态机接收器,花时间确保信息以正确的顺序更新。

编辑:从.NET 4.0开始,您可以使用ConcurrentQueue(T) Class来获得相同的结果。