Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        // 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;
            }
        }
Example #4
0
        //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);
        }
Example #5
0
 public new void Add(ObservableSource <T> os)
 {
     if (os == null)
     {
         throw new InvalidOperationException("Items of an OSCollection cannot be null.");
     }
     base.Add(os);
 }
Example #6
0
        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);
        }
Example #7
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
        }