コード例 #1
0
        protected virtual ObservableSourceProvider GetSourceRoot(BindingTarget bindingTarget, object source,
                                                                 string pathElement = ROOT_PATH_ELEMENT, string binderName = DEFAULT_BINDER_NAME)
        {
            ObservableSourceProvider osp = ObservableSourceProvider.GetSourceRoot(bindingTarget, source, pathElement, binderName);

            return(osp);
        }
コード例 #2
0
ファイル: ObservableSource.cs プロジェクト: drminor/propbag
        private ObservableSourceProvider GetChildFromPropBag(IPropBag data, Type type, string pathElement)
        {
            object newData;
            Type   newType;

            if (data.TryGetPropGen(pathElement, null, out IPropData iPg))
            {
                newData = iPg?.TypedProp.TypedValueAsObject;
                newType = iPg?.TypedProp.PropTemplate.Type;

                if (newData != null)
                {
                    ObservableSourceProvider child = CreateChild(newData, newType, pathElement);
                    return(child);
                }
                else
                {
                    return(new ObservableSourceProvider(pathElement, newType, PathConnectorTypeEnum.Dot, BinderName));
                }
            }
            else
            {
                // Property value could not be retreived.
                if (data.TryGetTypeOfProperty(pathElement, out newType))
                {
                    // Create an ObservableSource with SourceKind = TerminalNode.
                    return(new ObservableSourceProvider(pathElement, newType, PathConnectorTypeEnum.Dot, BinderName));
                }
                else
                {
                    return(null);
                }
            }
        }
コード例 #3
0
 public static bool GetSourceFromSource(object source, string pathElement, string binderName, out ObservableSourceProvider osp)
 {
     if (source is DataSourceProvider)
     {
         osp = new ObservableSourceProvider(source as DataSourceProvider, pathElement, PathConnectorTypeEnum.Dot, binderName);
         return(true);
     }
     else if (source is INotifyPCGen)
     {
         osp = new ObservableSourceProvider(source as INotifyPCGen, pathElement, PathConnectorTypeEnum.Dot, binderName);
         return(true);
     }
     else if (source is INotifyPropertyChanged)
     {
         osp = new ObservableSourceProvider(source as INotifyPropertyChanged, pathElement, PathConnectorTypeEnum.Dot, binderName);
         return(true);
     }
     else if (source is INotifyCollectionChanged)
     {
         osp = new ObservableSourceProvider(source as INotifyCollectionChanged, pathElement, PathConnectorTypeEnum.Dot, binderName);
         return(true);
     }
     else
     {
         osp = null;
         return(false);
     }
 }
コード例 #4
0
        public static bool GetDefaultSource(BindingTarget bindingTarget, string pathElement,
                                            string binderName, out ObservableSourceProvider osp)
        {
            bool isTargetADc = bindingTarget.IsDataContext;

            if (bindingTarget.DependencyObject is FrameworkElement fe)
            {
                osp = new ObservableSourceProvider(fe, pathElement, isTargetADc, PathConnectorTypeEnum.Dot, binderName);
                return(true);
            }
            else if (bindingTarget.DependencyObject is FrameworkContentElement fce)
            {
                osp = new ObservableSourceProvider(fce, pathElement, isTargetADc, PathConnectorTypeEnum.Dot, binderName);
                return(true);
            }
            else if (bindingTarget.DependencyObject is DataGridColumn dgc)
            {
                osp = new ObservableSourceProvider(dgc, pathElement, PathConnectorTypeEnum.Dot, binderName);
                return(false);
            }
            else
            {
                osp = null;
                return(false);
            }
        }
コード例 #5
0
ファイル: ObservableSource.cs プロジェクト: drminor/propbag
        private ObservableSourceProvider GetChildFromClr(object data, Type type, string pathElement)
        {
            if (data != null)
            {
                object val = GetMemberValue(pathElement, data, type, this.PathElement,
                                            out Type pt);

                ObservableSourceProvider child = CreateChild(val, pt, pathElement);
                return(child);
            }
            else
            {
                // Using reflection, get the type.
                Type pt = GetTypeOfPathElement(pathElement, type, this.PathElement);

                // Create an ObservableSource with SourceKind = TerminalNode.
                return(new ObservableSourceProvider(pathElement, pt, PathConnectorTypeEnum.Dot, BinderName));
            }
        }
コード例 #6
0
        protected bool RefreshPathListeners(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType, OSCollection pathListeners,
                                            DataSourceChangedEventArgs changeInfo, ObservableSource signalingOs)
        {
            // Assume that this operation will not require the binding to be updated,
            // until proven otherwise.
            bool bindingInfoChanged = false;

            int nodeIndex = _dataSourceChangeListeners.IndexOf(signalingOs);

            if (nodeIndex == -1)
            {
                throw new InvalidOperationException($"Could not get pointer to path element while processing " +
                                                    $"DataSourceChanged event for {BinderName} in PropBagControlsWPF.Binders.");
            }

            ObservableSource           parentOs = pathListeners[nodeIndex];
            ObservableSourceStatusEnum status;

            // Initializing
            // Attempt to get a reference to the Source Root (Object with DataContext property or DataSourceProvider.)
            if (changeInfo.ChangeType == DataSourceChangeTypeEnum.Initializing)
            {
                System.Diagnostics.Debug.Assert(nodeIndex == ROOT_INDEX, $"The node index should refer to the ObservableSource for " +
                                                $"the root when DataSourceChangeType = {nameof(DataSourceChangeTypeEnum.Initializing)}.");

                string rootElementName       = GetRootPathElementName(pathListeners);
                ObservableSourceProvider osp = GetSourceRoot(bindingTarget, bInfo.Source, rootElementName, BinderName);

                if (osp == null)
                {
                    throw new InvalidOperationException($"{BinderName} could not locate a data source.");
                }

                status = pathListeners.ReplaceListener(ROOT_INDEX, ref osp, this.DataSourceHasChanged,
                                                       out parentOs);

                if (parentOs?.IsListeningForNewDC != true)
                {
                    throw new InvalidOperationException($"{BinderName} could not locate a data source.");
                }
            }

            // DataContextUpdated
            // Refresh the Source Root
            else if (changeInfo.ChangeType == DataSourceChangeTypeEnum.DataContextUpdated)
            {
                System.Diagnostics.Debug.Assert(nodeIndex == ROOT_INDEX, $"The node index should refer to the ObservableSource for" +
                                                $" the root when DataSourceChangeType = {nameof(DataSourceChangeTypeEnum.DataContextUpdated)}.");

                status = parentOs.Status;

                pathListeners.ResetListeners(ROOT_INDEX + 1, this.DataSourceHasChanged);
                bindingInfoChanged = true;
            }

            // Handle Collection Change
            else if (changeInfo.ChangeType == DataSourceChangeTypeEnum.CollectionChanged)
            {
                return(bindingInfoChanged);
            }

            // Handle Property Changed
            else if (changeInfo.ChangeType == DataSourceChangeTypeEnum.PropertyChanged)
            {
                // The PropModel of the value of this node's child may have changed.
                // Replace the child with a new SourceListner, if appropriate
                // and then fall-through to normal processing, at signaled step + 2.

                string changedPropName = changeInfo.PropertyName;

                nodeIndex++;
                ObservableSource child   = pathListeners[nodeIndex];
                bool             matched =
                    changedPropName == child.NewPathElement ||
                    changedPropName == "Item[]" && child.NewPathElement.StartsWith("[");

                if (!matched || !(nodeIndex < pathListeners.Count - 1))
                {
                    // Action is not required if
                    // The updated property is not part of our path,
                    // or our child in the terminal node,
                    return(bindingInfoChanged);
                }

                // Replace the child, if
                //  1. It was null and now is not, or
                //  2. It is now null and was not null, or
                //  3. It was PropBag-based and is now is not, or
                //  4. It was a regular CLR object and is now PropBag-based, or
                //  5. It is still PropBag-Based and the prop item corresponding
                //      to the grandchild node had a change in type.

                if (!child.Status.IsReadyOrWatching())
                {
                    string prevValueForNewPathElement         = child.NewPathElement;
                    ObservableSourceProvider newChildProvider = parentOs.GetChild(child.PathElement);

                    if (newChildProvider?.Data == null)
                    {
                        // Still no data ??
                        System.Diagnostics.Debug.WriteLine("Child was null and is still null.");

                        //ResetPathListeners(pathListeners, nodeIndex);
                        pathListeners.ResetListeners(nodeIndex, this.DataSourceHasChanged);


                        bindingInfoChanged = true;
                        return(bindingInfoChanged);
                    }

                    //ObservableSourceStatusEnum newCStatus =
                    //    ReplaceListener(pathListeners, nodeIndex, ref newChildProvider,
                    //    this.DataSourceHasChanged, out ObservableSource newChild);

                    ObservableSourceStatusEnum newCStatus = pathListeners.ReplaceListener(nodeIndex, ref newChildProvider,
                                                                                          this.DataSourceHasChanged, out ObservableSource newChild);

                    if (newChild != null)
                    {
                        string newPathElement = GetNewPathElement(newChild.PathElement, newChild.Type, parentOs.IsPropBagBased);
                        newChild.NewPathElement = newPathElement;

                        bindingInfoChanged = (newPathElement != prevValueForNewPathElement);
                    }
                }

                // If the child was updated, begin processing our grand children.
                parentOs = pathListeners[nodeIndex];
                status   = parentOs?.Status ?? ObservableSourceStatusEnum.NoType;
            }
            else
            {
                throw new ApplicationException($"The DataSourceChangedType: {changeInfo.ChangeType} is not recognized.");
            }

            // Now, starting at step: stepNo + 1, replace or refresh each listener.

            int nPtr = nodeIndex + 1;

            for (; nPtr < pathListeners.Count - 1 && status.IsReadyOrWatching(); nPtr++)
            {
                // This is an itermediate step and the path has at least two components.

                parentOs.BeginListeningToSource();
                if (nPtr > 1)
                {
                    // Make sure we are listening to events that this ObservableSource may raise.
                    // We know that we are subscribed to the root.
                    parentOs.Subscribe(this.DataSourceHasChanged);
                }

                string pathElement = pathListeners[nPtr].PathElement;
                string prevValueForNewPathElement = pathListeners[nPtr].NewPathElement;

                ObservableSourceProvider osp = parentOs.GetChild(pathElement);

                //status = ReplaceListener(pathListeners, nPtr, ref osp, this.DataSourceHasChanged,
                //    out ObservableSource os);

                status = pathListeners.ReplaceListener(nPtr, ref osp, this.DataSourceHasChanged,
                                                       out ObservableSource os);

                if (os != null)
                {
                    string newPathElement = GetNewPathElement(pathElement, os.Type, parentOs.IsPropBagBased);
                    os.NewPathElement = newPathElement;

                    bindingInfoChanged = (newPathElement != prevValueForNewPathElement);
                }
                // Note: if os is null, status will be "NoType", i.e. not ready.

                if (status == ObservableSourceStatusEnum.Ready)
                {
                    System.Diagnostics.Debug.WriteLine($"Listener for {pathElement} is ready.");
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine($"Listener for {pathElement} is not ready.");
                }

                parentOs = os;
                //status = os.Status; -- Not needed, ReplaceListener sets this variable.
            }

            if (nPtr == pathListeners.Count - 1)
            {
                // Process terminal node.
                ObservableSource lastNode = pathListeners[nPtr];
                if (status.IsReadyOrWatching())
                {
                    string newPathElement = GetNewPathElement(lastNode.PathElement, lastNode.Type, parentOs.IsPropBagBased);
                    if (lastNode.NewPathElement != newPathElement)
                    {
                        lastNode.NewPathElement = newPathElement;
                        bindingInfoChanged      = true;
                    }
                    if (!status.IsWatching())
                    {
                        parentOs.BeginListeningToSource();
                    }
                }
            }
            else
            {
                // Don't have all of the data present required to create a binding.
                System.Diagnostics.Debug.WriteLine($"RefreshPathListeners claims that no binding should be created for path = {bInfo.PropertyPath.Path}.");
                //ResetPathListeners(pathListeners, nPtr);
                pathListeners.ResetListeners(nPtr, this.DataSourceHasChanged);
            }

            return(bindingInfoChanged);
        }
コード例 #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="pathListeners"></param>
        /// <param name="index"></param>
        /// <param name="newListenerProvider"></param>
        /// <param name="subscriber"></param>
        /// <param name="newListener"></param>
        /// <returns>True if the path listener is ready to start listening to property and/or collection change events.</returns>
        public ObservableSourceStatusEnum ReplaceListener(int index, ref ObservableSourceProvider newListenerProvider,
                                                          DataSourceChangedEventHandler subscriber, out ObservableSource newListener)
        {
            if (index == Count - 1)
            {
                System.Diagnostics.Debug.Assert(index != Count - 1,
                                                "We are replacing the terminal listener. This is not good.");
            }

            ObservableSource oldListener = this[index];

            if (newListenerProvider != null)
            {
                newListener = newListenerProvider.CreateObservableSource(); newListenerProvider = null;
            }
            else
            {
                newListener = null;
            }

            bool wasListening = oldListener?.IsListeningForNewDC == true;

            if (newListener?.IsListeningForNewDC != true)
            {
                // The new ObservableSource is not responding to any change events.
                if (index == 0)
                {
                    System.Diagnostics.Debug.WriteLine("The Source Root is not listening.");
                }
                else if (wasListening)
                {
                    System.Diagnostics.Debug.WriteLine($"The ObservableSource at node {index} is no longer listening to any change events.");
                }
            }

            if (oldListener != null)
            {
#if DEBUG
                bool wasRemoved = oldListener.Unsubscribe(subscriber);
                System.Diagnostics.Debug.Assert(wasListening == wasRemoved, "Was Listening does not agree with WasRemoved.");

                // Remove PropertyChanged or CollectionChanged event handlers, if any.
                oldListener.Reset();
#else
                // Remove all event handlers.
                oldListener.Reset(subscriber);
#endif
            }

            if (newListener == null)
            {
                // It is the caller's responsibility to cleanup the dependent nodes.
                return(ObservableSourceStatusEnum.NoType);
            }

            if (newListener.IsListeningForNewDC)
            {
                bool isListening = newListener.Subscribe(subscriber);
                System.Diagnostics.Debug.Assert(isListening, "Subscriber was already present, but should not have been.");
                isListening = newListener.IsListeningForNewDC;
            }

            this[index] = newListener;

#if DEBUG
            bool hasType = newListener.GetHasTypeAndHasData(out bool hasData);
#endif

            // The new path listener is ready to start monitoring Property and/or Collection Changed events if
            // it still has a reference to the object that will be monitored.
            return(newListener.Status);
        }