private bool AddOrUpdateListener(BagNode propStoreNode, string pathComp, SourceKindEnum sourceKind, OSCollection <T> pathListeners, int nPtr) { bool result; if (pathListeners.Count > nPtr) { ObservableSource <T> listener = pathListeners[nPtr]; if (propStoreNode.CompKey != listener.CompKey || sourceKind != listener.SourceKind) { listener.Dispose(); ObservableSource <T> newListener = CreateAndListen(propStoreNode, pathComp, sourceKind); pathListeners[nPtr] = newListener; result = true; } else { result = false; } } else { ObservableSource <T> newListener = CreateAndListen(propStoreNode, pathComp, sourceKind); pathListeners.Add(newListener); result = true; } return(result); }
private ObservableSource <T> CreateAndListen(BagNode propStoreNode, string pathComp, SourceKindEnum sourceKind) { ObservableSource <T> result = new ObservableSource <T>(propStoreNode, propStoreNode.CompKey, pathComp, sourceKind, BINDER_NAME); result.ParentHasChanged += ParentHasChanged_Handler; return(result); }
// Base Constructor private LocalWatcher(PSAccessServiceInterface propStoreAccessService, LocalBindingInfo bindingInfo) { if (propStoreAccessService is PSAccessServiceInternalInterface propStoreAccessService_Internal) { _propStoreAccessService_wr = new WeakReference <PSAccessServiceInternalInterface>(propStoreAccessService_Internal); } else { throw new InvalidOperationException($"The propStoreAcccessService does not implement the internal interface: {nameof(PSAccessServiceInternalInterface)}."); } _ourNode = GetPropBagNode(propStoreAccessService); _bindingInfo = bindingInfo; _pathListeners = new OSCollection <T>(); BindingPathParser pathParser = new BindingPathParser(); _pathElements = pathParser.GetPathElements(bindingInfo, out _isPathAbsolute, out _firstNamedStepIndex); if (_isPathAbsolute) { _rootListener = CreateAndListen(_ourNode, "root", SourceKindEnum.AbsRoot); } else { _rootListener = null; } }
//Lazy<IValueConverter> _defaultConverter; //public virtual Lazy<IValueConverter> DefaultConverter //{ // get // { // if(_defaultConverter == null) // { // return new Lazy<IValueConverter>(() => new PropValueConverter()); // } // return _defaultConverter; // } // set // { // _defaultConverter = value; // } //} //Func<BindingTarget, MyBindingInfo, Type, string, object> _defConvParamBuilder; //public virtual Func<BindingTarget, MyBindingInfo, Type, string, object> DefaultConverterParameterBuilder //{ // get // { // if (_defConvParamBuilder == null) // { // return OurDefaultConverterParameterBuilder; // } // return _defConvParamBuilder; // } // set // { // _defConvParamBuilder = value; // } //} #endregion #region Constructor internal LocalBinder(PSAccessServiceInterface propStoreAccessService, LocalBindingInfo bindingInfo, IReceivePropStoreNodeUpdates storeNodeUpdateReceiver) { _propStoreAccessService_wr = new WeakReference <PSAccessServiceInterface>(propStoreAccessService); _bindingInfo = bindingInfo; _storeNodeUpdateReceiver = storeNodeUpdateReceiver; _bindingTarget = new SimpleExKey(); // Get the PropStore Node for the IPropBag object hosting the property that is the target of the binding. // TODO: Instead of doing this now, create a property that allows us to access upon first access. _ourNode = GetPropBagNode(propStoreAccessService); _targetObject = null; _propertyName = null; _targetHasStore = PropStorageStrategyEnum.Virtual; _pathElements = GetPathElements(_bindingInfo, out _isPathAbsolute, out _firstNamedStepIndex); if (_isPathAbsolute) { _rootListener = CreateAndListen(_ourNode, "root", SourceKindEnum.AbsRoot); } else { _rootListener = null; } _pathListeners = new OSCollection <T>(); _isComplete = StartBinding(_targetObject, _pathElements, _pathListeners, _isPathAbsolute); }
public new void Add(ObservableSource <T> os) { if (os == null) { throw new InvalidOperationException("Items of an OSCollection cannot be null."); } base.Add(os); }
private ObservableSource <T> CreateAndListen(IPropBag propBag, ExKeyT compKey, string pathComp, SourceKindEnum sourceKind) { ObservableSource <T> result; if (sourceKind == SourceKindEnum.Down) { result = new ObservableSource <T>((IPropBag)propBag, compKey, pathComp, sourceKind, BINDER_NAME); result.PropertyChangedWithVals += PropertyChangedWithVals_Handler; } else if (sourceKind == SourceKindEnum.TerminalNode) { result = new ObservableSource <T>((IPropBag)propBag, compKey, pathComp, BINDER_NAME); result.PropertyChangedWithTVals += PropertyChangedWithTVals_Handler; } else { throw new InvalidOperationException($"CreateAndListen when supplied a propBag can only process nodes of source kind = {nameof(SourceKindEnum.Down)} and {nameof(SourceKindEnum.TerminalNode)}."); } return(result); }
public LocalBinder(PSAccessServiceInterface propStoreAccessService, ExKeyT ownerPropId, LocalBindingInfo bindingInfo) { _propStoreAccessService_wr = new WeakReference <PSAccessServiceInterface>(propStoreAccessService); _bindingTarget = ownerPropId; _bindingInfo = bindingInfo; _storeNodeUpdateReceiver = null; // Get the PropStore Node for the IPropBag object hosting the property that is the target of the binding. _ourNode = GetPropBagNode(propStoreAccessService); PropIdType propId = _bindingTarget.Level2Key; _targetObject = _ourNode.PropBagProxy; if (_targetObject.TryGetTarget(out IPropBagInternal propBag)) { _propertyName = GetPropertyName(propStoreAccessService, propBag, propId, out PropStorageStrategyEnum storageStrategy); _targetHasStore = storageStrategy; } _pathElements = GetPathElements(_bindingInfo, out _isPathAbsolute, out _firstNamedStepIndex); if (_isPathAbsolute) { _rootListener = CreateAndListen(_ourNode, "root", SourceKindEnum.AbsRoot); } else { _rootListener = null; } _pathListeners = new OSCollection <T>(); _isComplete = StartBinding(_targetObject, _pathElements, _pathListeners, _isPathAbsolute); }
private bool DataSourceHasChanged_Handler(ObservableSource <T> signalingNode, DataSourceChangeTypeEnum changeType, out PropNode sourcePropNode) { sourcePropNode = null; bool isComplete = false; BagNode next; switch (signalingNode.SourceKind) { case SourceKindEnum.AbsRoot: { System.Diagnostics.Debug.Assert(changeType == DataSourceChangeTypeEnum.ParentHasChanged, $"Received a DataSourceChanged event from on a node of kind = AbsRoot. " + $"The DataSourceChangeType should be {nameof(DataSourceChangeTypeEnum.ParentHasChanged)}, but is {changeType}."); System.Diagnostics.Debug.Assert(ReferenceEquals(signalingNode, _rootListener), "Received a ParentHasChanged on a node of kind = AbsRoot and the signaling node is not the _rootListener."); System.Diagnostics.Debug.Assert(_isPathAbsolute, "Received a ParentHasChanged on a node of kind = AbsRoot, but our 'PathIsAbsolute' property is set to false."); // We have a new root, start at the beginning. next = _ourNode.Root; if (next == null) { System.Diagnostics.Debug.WriteLine("OurNode's root is null when processing update to AbsRoot."); return(isComplete); } int nPtr = 0; isComplete = HandleNodeUpdate(next, _pathElements, _pathListeners, nPtr, out sourcePropNode); break; } case SourceKindEnum.Up: { System.Diagnostics.Debug.Assert(changeType == DataSourceChangeTypeEnum.ParentHasChanged, $"DataSourceHasChanged is processing a observable source of kind = {signalingNode.SourceKind}, but the ChangeType does not equal {nameof(DataSourceChangeTypeEnum.ParentHasChanged)}."); if (GetChangedNode(_ourNode, signalingNode, _isPathAbsolute, _pathElements, out next, out int nPtr)) { System.Diagnostics.Debug.Assert(nPtr < _pathElements.Length - 1, "GetChangedNode for 'up' PropertyChanged event returned with nPtr beyond next to last node."); isComplete = HandleNodeUpdate(next, _pathElements, _pathListeners, nPtr, out sourcePropNode); } break; } case SourceKindEnum.Down: { System.Diagnostics.Debug.Assert(changeType == DataSourceChangeTypeEnum.PropertyChanged, $"DataSourceHasChanged is processing a observable source of kind = {signalingNode.SourceKind}, but the ChangeType does not equal {nameof(DataSourceChangeTypeEnum.PropertyChanged)}."); if (GetChangedNode(_ourNode, signalingNode, _isPathAbsolute, _pathElements, out next, out int nPtr)) { System.Diagnostics.Debug.Assert(nPtr < _pathElements.Length - 1, "GetChangedNode for 'down' PropertyChanged event returned with nPtr beyond next to last node."); isComplete = HandleNodeUpdate(next, _pathElements, _pathListeners, nPtr, out sourcePropNode); } break; } case SourceKindEnum.TerminalNode: { System.Diagnostics.Debug.Assert(Complete, "The Complete flag should be set when responding to Terminal node updates."); System.Diagnostics.Debug.WriteLine("Beginning to proccess property changed event raised from the Terminal node of the source path."); if (GetChangedNode(_ourNode, signalingNode, _isPathAbsolute, _pathElements, out next, out int nPtr)) { isComplete = HandleTerminalNodeUpdate(next, _pathElements, nPtr, out sourcePropNode); } break; } default: { throw new InvalidOperationException($"The SourceKind: {signalingNode.SourceKind} is not recognized or is not supported."); } } return(isComplete); }
private bool GetChangedNode(BagNode ourNode, ObservableSource <T> signalingNode, bool pathIsAbsolute, string[] pathElements, out BagNode next, out int nPtr) { int startIndex = _pathListeners.IndexOf(signalingNode); if (startIndex == -1) { throw new InvalidOperationException($"Could not get pointer to path element while processing DataSourceChanged event for {BINDER_NAME}."); } if (pathIsAbsolute) { SourceKindEnum sourceKind = signalingNode.SourceKind; System.Diagnostics.Debug.Assert(sourceKind == SourceKindEnum.Down || sourceKind == SourceKindEnum.TerminalNode, $"When the source path is absolute, GetChangedNode can only be called for a node whose kind is {nameof(SourceKindEnum.Down)} or {nameof(SourceKindEnum.TerminalNode)}."); next = ourNode.Root; if (next == null) { if (sourceKind == SourceKindEnum.Down) { System.Diagnostics.Debug.WriteLine("OurNode's root is null when processing DataSource Changed for 'intervening' node."); } else { System.Diagnostics.Debug.WriteLine("OurNode's root is null when processing Terminal node."); } nPtr = 0; return(false); } } else { next = ourNode; } // For terminal nodes: // Initially startIndex should point to the last path element. // On exit, next be the PropBag that owns the binding source propItem // and nPtr should point to the last listener. // For intervening nodes: // Initially startIndex should point to the element that was changed. // On exit, next should be the PropBag that owns the propItem of the property that was changed // and nPtr should point to the listener that changed. for (nPtr = 0; next != null && nPtr < startIndex; nPtr++) { string pathComp = pathElements[nPtr]; if (pathComp == "..") { next = next.Parent?.Parent; } else { if (TryGetPropBag(next, out IPropBag propBag)) { if (TryGetChildProp(next, /*propBag,*/ pathComp, out PropNode child)) { if (nPtr + 1 == pathElements.Length - 1) { // next is set to the node we wan't and we can access the child. } else { // Get the PropBag being hosted by this current object's property. next = child.Child; } } else { System.Diagnostics.Debug.WriteLine("Could not get reference to the PropItem's PropStoreNode during binding update."); next = null; } } else { System.Diagnostics.Debug.WriteLine("The weak reference to the PropBag refers to a ProBag which 'is no longer with us.'"); next = null; } } } return(next != null); }
private bool HandleNodeUpdate(BagNode next, string[] pathElements, OSCollection <T> pathListeners, int nPtr, out PropNode sourcePropNode) { bool complete = false; sourcePropNode = null; // Process each step, except for the last. for (; next != null && nPtr < pathElements.Length - 1; nPtr++) { string pathComp = pathElements[nPtr]; if (pathComp == "..") { bool listenerWasAdded = AddOrUpdateListener(next, pathComp, SourceKindEnum.Up, pathListeners, nPtr); string mg = listenerWasAdded ? "added" : "updated"; System.Diagnostics.Debug.WriteLine($"The Listener for step: {pathComp} was {mg}."); next = next.Parent?.Parent; } else { if (TryGetPropBag(next, out IPropBag propBag)) { bool listenerWasAdded = AddOrUpdateListener(propBag, next.CompKey, pathComp, SourceKindEnum.Down, pathListeners, nPtr); string mg = listenerWasAdded ? "added" : "updated"; System.Diagnostics.Debug.WriteLine($"The Listener for step: {pathComp} was {mg}."); if (TryGetChildProp(next, /*propBag, */ pathComp, out PropNode child)) { next = child.Child; } else { System.Diagnostics.Debug.WriteLine("Could not get reference to the PropItem's PropStoreNode during binding update."); next = null; } } else { System.Diagnostics.Debug.WriteLine("The weak reference to the PropBag refers to a ProBag which 'is no longer with us.'"); next = null; } } } // Add the terminal node. if (next != null) { System.Diagnostics.Debug.Assert(nPtr == pathElements.Length - 1, $"The counter variable: nPtr should be {pathElements.Length - 1}, but is {nPtr} instead."); if (TryGetPropBag(next, out IPropBag propBag)) { string pathComp = pathElements[nPtr]; bool listenerWasAdded = AddOrUpdateListener(propBag, next.CompKey, pathComp, SourceKindEnum.TerminalNode, pathListeners, nPtr); string mg = listenerWasAdded ? "added" : "updated"; System.Diagnostics.Debug.WriteLine($"The Listener for terminal step: {pathComp} was {mg}."); // We have created or updated the listener for this step, advance the pointer. nPtr++; // We have subscribed to the property that is the source of the binding. complete = true; // Let's try to get the value of the property for which we just started listening to changes. if (TryGetChildProp(next, /*propBag,*/ pathComp, out sourcePropNode)) { if (NotifyReceiverWithStartingValue(sourcePropNode)) { System.Diagnostics.Debug.WriteLine($"The receiver has been notified during refresh. " + $"Source: {((IPropBag)propBag).FullClassName}, {pathComp}"); } else { System.Diagnostics.Debug.WriteLine("The binding source has been reached, but the receiver was not notified during refresh. " + $"Source: {((IPropBag)propBag).FullClassName}, {pathComp}"); } } else { System.Diagnostics.Debug.WriteLine("Could not get reference to the PropItem's PropStoreNode during binding update."); } } else { System.Diagnostics.Debug.WriteLine("The weak reference to the PropBag refers to a ProBag which 'is no longer with us.'"); } } for (; nPtr < pathListeners.Count; nPtr++) { ObservableSource <T> listener = pathListeners[nPtr]; listener.Dispose(); pathListeners.RemoveAt(nPtr); } return(complete); }