Skip to content

Creating an unowned CmPossibilityList issues no PropChanged #397

Description

@jasonleenaylor

Gap

IUnitOfWorkService.RegisterObjectAsCreated (src/SIL.LCModel/Infrastructure/Impl/UnitOfWorkService.cs:583) records creation as an LcmStateChangeObjectCreation (src/SIL.LCModel/Infrastructure/Impl/LcmStateChangingClasses.cs:279). That class derives from LcmStateChangeBase and does not implement ILcmPropertyChanged. UnitOfWork.GetPropChangeInformation (src/SIL.LCModel/Infrastructure/Impl/UnitOfWork.cs:621) yields only from actions that implement ILcmPropertyChanged, so object creation by itself produces no ChangeInformation.

For an owned object the PropChanged arrives from the owning property's LcmVectorPropertyChanged / LcmAtomicRefPropertyChanged. An unowned object has no owning property, so no IVwNotifyChange.PropChanged is issued at all. This is the open TODO at UnitOfWorkService.cs:599:

// (TODO: What needs to be done for unowned objects?)

ICmPossibilityListFactory.CreateUnowned (src/SIL.LCModel/DomainImpl/FactoryAdditions.cs:1560) hits this. The new CmPossibilityList is registered in the IdentityMap, is returned by ICmPossibilityListRepository.AllInstances(), and is persisted as a UOW newbie — but no client receives a PropChanged, so nothing that caches a view of the lists is told to reload.

Proposed fix

Apply the pattern already used for the other unowned classes:

  • LexEntry.RegisterVirtualsModifiedForObjectCreation (src/SIL.LCModel/DomainImpl/OverridesLing_Lex.cs:854) → Virtuals.LexDbEntries
  • Text.RegisterVirtualsModifiedForObjectCreation / ...ForObjectDeletion (src/SIL.LCModel/DomainImpl/OverridesLing_Wfi.cs:1713 and :1746) → Virtuals.LangProjTexts
  1. Add a Virtuals accessor for LangProject.AllPossibilityLists, which already exists as a virtual property (src/SIL.LCModel/DomainImpl/OverridesLangProj.cs:83, declared [VirtualProperty(CellarPropertyType.ReferenceCollection, "CmPossibilityList")]). Model it on Virtuals.LangProjTexts (src/SIL.LCModel/DomainImpl/Virtuals.cs:205).

  2. On CmPossibilityList, override RegisterVirtualsModifiedForObjectCreation and RegisterVirtualsModifiedForObjectDeletion (src/SIL.LCModel/DomainImpl/CmObject.cs:1758 and :1769) to call uow.RegisterVirtualCollectionAsModified for that flid on Cache.LangProject, and invoke them from SetDefaultValuesAfterInit / OnBeforeObjectDeleted the way Text does.

  3. Make CmPossibilityListFactory.CreateUnowned call ((ICmObjectInternal)result).InitializeNewOwnerlessCmObjectWithPresetGuid() before returning, matching the generated ownerless CmPossibilityListFactory.Create(Guid) (src/SIL.LCModel/DomainImpl/GeneratedFactoryImplementations.cs:320-327). Without this, SetDefaultValuesAfterInit never runs on the CreateUnowned path and the hook added in step 2 would not fire.

ChangeReconciler.ReconcileForeignChanges already calls RegisterVirtualsModifiedForObjectCreation on each foreign newby (src/SIL.LCModel/Infrastructure/Impl/ChangeReconciler.cs:212), so step 2 also covers Send/Receive and second-window reconciliation.

Note that SetDefaultValuesAfterInit also runs during bootstrap and data migration, where Cache.LangProject may not be resolvable; LexEntry and Text carry the same exposure, so follow whatever guard they rely on.

Out of scope

Custom field metadata is a separate mechanism with no notification path at all: LcmMetaDataCache.AddCustomField / UpdateCustomField / DeleteCustomField mutate m_metaFieldRecords in place, and FieldDescription.UpdateCustomField registers affected objects as modified but registers no metadata change. Clients must continue to be notified manually after adding a custom field.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions