/// <summary> /// Update an entry in the list with data from an alarm /// </summary> /// <param name="i">Index in the list to update</param> /// <param name="alarm">Alarm with the new data to display</param> private void UpdateCollectionItem(int i, ObservableAlarmLine alarm) { // Local ID and message are assumed not to change if (_alarmObserverCollection[i].Priority != alarm.Priority) { _alarmObserverCollection[i].Priority = alarm.Priority; } if (_alarmObserverCollection[i].State != alarm.State) { _alarmObserverCollection[i].State = alarm.State; } }
/// <summary> /// Display a smoothly scrolling list of the 10 newest alarms /// </summary> public void onAlarmsReceivedMethod() { try { // If you know that your alarms are all new, you may clear the observable list and fill in from scratch, but that may cause flickering. // The algorithm here is to avoid such flickering. It is a mini version of the code from the Smart Client plug-in. int bottomIndex = _alarms.Length - 1; for (int i = 0; i <= bottomIndex; i++) { // We assume that the alarms received are always ordered by time descending, and the Alarm.ID is unique per instance of an Alarm // Thus is is given that if a given ID is ordered after another ID once, it will always be after that other ID. // // There are two possibilities // A: The received item is new and does not appear in the collection, // in which case we just add it to the top of the collection, but after those new ones already added // B: The received item appears at this or a later position in the old collection // in which case the old ones from the current position to the match position must have disappeared // All those items are removed and the matching item is updated ObservableAlarmLine alarm = new ObservableAlarmLine(_alarms[i]); int match = FindId(i, alarm.AlarmLine.Id); if (match == -1) { // The alarm is inserted as a new item, because it did not appear in the former collection _alarmObserverCollection.Insert(i, alarm); } else { // If the match was some positions ahead, we are sure that those alarms skipped shall no longer be displayed // Remember not to advance the index passed to RemoveAt(). When we have deleted position i, the old i+1 is not at the same position. for (int j = i; j < match; j++) { _alarmObserverCollection.RemoveAt(i); } // We must then update the individual properties of the alarm in the list with those property values from the new alarm // Just setting _alarmObserverCollection[i] = alarm cause the WPF list view's multiple selection mechanism to get confused. UpdateCollectionItem(i, alarm); } } // If the number of alarms received is less than in the original collection, we are left with a tail of alarms, which we don't know the actual status of // Most likely, they will exist unaltered, but they may have had their data changed or they might have been deleted. We do not know that for sure. // This implementation therefore removes them, which may cause selected items to disappear from the list view // The exception is an empty list caused by a temporary connect error, where we want to keep all the old data // If the list really it to be cleared, _eraseAlarmListBeforeUpdate should have been set to true if (bottomIndex > 0) { int n = _alarmObserverCollection.Count - 1; while (n > bottomIndex) { _alarmObserverCollection.RemoveAt(n); n--; } } } catch (Exception) { // Go on. This is just for safety. } }