/// <summary> /// update the contents of the tree bar and anything else that should change when, /// for example, the filter or sort order changes. /// </summary> protected void OnListChanged(object src, ListChangedEventArgs arguments) { if (IsControllingTheRecordTreeBar) // m_treeBarHandler!= null) { if (arguments.Actions == ListChangedEventArgs.ListChangedActions.UpdateListItemName) { // ****************************************************************************** // In the case where there are no other items and the Current object isn't valid, // then just don't do anything. LT-5849. // A more robust solution would be to have in our design a way to produce // a 'defered' prop changed so that the current actions can finish before // others are notified of the change (which is often incomplete at that time). // The stack for this issue showed the RecordList and RecordClerk being // re-entered while they were deleting an object in a previous stack frame. // This is not the only case where this has been noted, but a solution has // not yet been thought of. // In the meantime, this fixed the crash .. <sigh> but doesn't help at all // for the other cases where this can happen. // ****************************************************************************** if (m_recordBarHandler is TreeBarHandler && m_list.CurrentObject != null && (m_list.CurrentObject.Cache != null || m_list.SortedObjects.Count != 1)) { // all we need to do is replace the currently selected item in the tree. var hvoItem = arguments.ItemHvo; ICmObject obj = null; if (hvoItem != 0) Cache.ServiceLocator.GetInstance<ICmObjectRepository>().TryGetObject(hvoItem, out obj); if (obj == null) obj = m_list.CurrentObject; m_recordBarHandler.ReloadItem(obj); } } else { m_recordBarHandler.PopulateRecordBar(m_list); } } if (arguments.Actions == ListChangedEventArgs.ListChangedActions.SkipRecordNavigation || arguments.Actions == ListChangedEventArgs.ListChangedActions.UpdateListItemName) { SelectedRecordChanged(true, false); } else if (arguments.Actions == ListChangedEventArgs.ListChangedActions.SuppressSaveOnChangeRecord) { bool oldSuppressSaveChangeOnRecord = SuppressSaveOnChangeRecord; SuppressSaveOnChangeRecord = true; try { BroadcastChange(false); } finally { SuppressSaveOnChangeRecord = oldSuppressSaveChangeOnRecord; } } else if (arguments.Actions == ListChangedEventArgs.ListChangedActions.Normal) { BroadcastChange(false); } else { throw new NotImplementedException("An enum choice for ListChangedEventArgs was selected that OnListChanged is not aware of."); } }
protected void SendPropChangedOnListChange(int newCurrentIndex, ArrayList newSortedObjects, ListChangedEventArgs.ListChangedActions actions) { //Populate the virtual cache property which will hold this set of hvos, in this order. int[] hvos = new int[newSortedObjects.Count]; int i = 0; foreach(ManyOnePathSortItem item in newSortedObjects) hvos[i++] = item.RootObject.Hvo; // In case we're already displaying it, we must have an accurate old length, or if it gets shorter // the extra ones won't get deleted. But we must check whether the property is already cached... // if it isn't and we try to read it, the code will try to load this fake property from the database, // with unfortunate results. (It's not exactly a reference sequence, but any sequence type will do here.) int rootHvo = m_owningObject.Hvo; int oldLength = 0; if (m_cache.MainCacheAccessor.get_IsPropInCache(rootHvo, m_virtualFlid, (int)CellarModuleDefns.kcptReferenceSequence, 0)) { oldLength = m_cache.MainCacheAccessor.get_VecSize(rootHvo, m_virtualFlid); } else { // on a general refresh operation all the caches get cleared before anything else // happens. So, use the old length that we stored earlier (cf. LT-2075). oldLength = m_oldLength; } if (AboutToReload != null) AboutToReload(this, new EventArgs()); // Must not actually change anything before we do AboutToReload! Then do it all at once // before we make any notifications...we want the cache value to always be consistent // with m_sortedObjects, and m_currentIndex always in range SortedObjects = newSortedObjects; // if we haven't already set an index, see if we can restore one from the property table. if (SortedObjects.Count > 0 && (newCurrentIndex == -1 || m_hvoCurrent == 0)) newCurrentIndex = m_mediator.PropertyTable.GetIntProperty(Clerk.PersistedIndexProperty, 0, PropertyTable.SettingsGroup.LocalSettings); // Ensure the index is in bounds. See LT-10349. if (SortedObjects.Count > 0) { // The stored value may be past the end of the current collection, // so set it to 0 in that case. // It sure beats the alternative of a drop dead crash. :-) if (newCurrentIndex > SortedObjects.Count - 1 || newCurrentIndex < 0) newCurrentIndex = 0; // out of bounds, so set it to 0. } else { newCurrentIndex = -1; } CurrentIndex = newCurrentIndex; m_cache.VwCacheDaAccessor.CacheVecProp(rootHvo, m_virtualFlid, hvos, hvos.Length); m_cache.MainCacheAccessor.PropChanged(this, (int)PropChangeType.kpctNotifyAllButMe, rootHvo, m_virtualFlid, 0, // Start at the beginning of the vector hvos.Length, // Pretend like we inserted and deleted them all, oldLength); // since we kind if did it that way. m_oldLength = hvos.Length; //TODO: try to stay on the same record /// Currently Attempts to keep us at the same index as we were. /// we should try hard to keep us on the actual record that we were currently on, /// since the reload may be a result of changing the sort order, in which case the index is meaningless. //make sure the hvo index is in a reasonable spot if (m_currentIndex >= hvos.Length) CurrentIndex = hvos.Length -1; if (m_currentIndex < 0) CurrentIndex = (hvos.Length>0)? 0: -1; if (DoneReload != null) DoneReload(this, new EventArgs()); // Notify any delegates that the selection of the main object in the vector has changed. if (ListChanged != null && m_fEnableSendPropChanged) ListChanged(this, new ListChangedEventArgs(this, actions)); }