Esempio n. 1
0
 public static bool IsReadyOrWatching(this ObservableSourceStatusEnum status)
 {
     return(status == ObservableSourceStatusEnum.Ready ||
            status == ObservableSourceStatusEnum.IsWatchingColl ||
            status == ObservableSourceStatusEnum.IsWatchingProp ||
            status == ObservableSourceStatusEnum.IsWatchingPropAndColl);
 }
Esempio n. 2
0
        //public void UpdateData()
        //{
        //    if (!(SourceKind == SourceKindEnum.FrameworkElement || SourceKind == SourceKindEnum.FrameworkContentElement || SourceKind == SourceKindEnum.DataSourceProvider || SourceKind == SourceKindEnum.DataGridColumn))
        //    {
        //        throw new InvalidOperationException($"Only ObservableSources with SourceKind =" +
        //            $" {nameof(SourceKindEnum.FrameworkElement)} or " +
        //            $"{nameof(SourceKindEnum.FrameworkContentElement)} " +
        //            $"{nameof(SourceKindEnum.DataSourceProvider)} " +
        //            $"can have their data updated.");
        //    }

        //    object newData;
        //    Type newType = null;
        //    ObservableSourceStatusEnum newStatus = ObservableSourceStatusEnum.NoType;

        //    if (SourceKind == SourceKindEnum.DataSourceProvider)
        //    {
        //        newData = ((DataSourceProvider)Container).Data;
        //        if (newData != null)
        //        {
        //            newType = newData.GetType();
        //        }

        //        newStatus = Status.SetReady(newData != null);
        //    }
        //    else
        //    {
        //        DependencyObject anchor = (DependencyObject)this.AnchorElement;
        //        if (!GetDcFromFrameworkElement(anchor, out newData, out newType, out newStatus))
        //        {
        //            throw new ApplicationException($"TargetObject in {this.BinderName}.ObservableSource was neither a FrameworkElement or a FrameworkContentElement.");
        //        }
        //    }

        //    UpdateData(newData, newType, newStatus);
        //}

        private bool UpdateData(object newData, Type newType, ObservableSourceStatusEnum newStatus)
        {
            if (!(SourceKind == SourceKindEnum.FrameworkElement ||
                  SourceKind == SourceKindEnum.FrameworkContentElement ||
                  SourceKind == SourceKindEnum.DataSourceProvider ||
                  SourceKind == SourceKindEnum.DataGridColumn))
            {
                throw new InvalidOperationException($"Only ObservableSources with SourceKind =" +
                                                    $" {nameof(SourceKindEnum.FrameworkElement)} or " +
                                                    $"{nameof(SourceKindEnum.FrameworkContentElement)} " +
                                                    $"{nameof(SourceKindEnum.DataSourceProvider)} " +
                                                    $"{nameof(SourceKindEnum.DataGridColumn)} " +
                                                    $"can have their data updated.");
            }

            bool   changed;
            object oldData = Data;

            if (oldData != null && newData != null)
            {
                if (object.ReferenceEquals(oldData, newData))
                {
                    System.Diagnostics.Debug.WriteLine("Update ObservableSource found identical data already present.");
                    changed = false;
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("Update ObservableSource found (different) data already present.");
                    changed = true;
                }
            }
            else if (!(oldData == null && newData == null) && (oldData == null || newData == null))
            {
                changed = true;
            }
            else
            {
                changed = false;
            }

            // Remove existing subscriptions if any for the existing Data.
            if (oldData != null && IsDcListening)
            {
                RemoveSubscriptions(oldData);
            }

            Data   = newData;
            Type   = newType;
            Status = newStatus;

            return(changed);
        }
Esempio n. 3
0
        protected Binding CreateTheBinding(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType,
                                           OSCollection pathListeners, out bool isCustom)
        {
            System.Diagnostics.Debug.Assert(sourceType != null, "The SourceType should never be null here.");

            // One node:    1 parent, 0 intervening objects, the terminal path element is "." -- The binding binds to the source data itself.
            // Two nodes:   1 parent, 0 intervening objects, 1 terminal path element.
            // Three nodes: 1 parent, 1 intervening object, 1 terminal path element.
            // Four nodes:  1 parent, 2 intervening objects, 1 terminal path element.

            // The next to last node, must have data, in order to avoid binding warnings.
            ObservableSource           lastParent       = pathListeners[pathListeners.Count - 2];
            string                     strNewPath       = pathListeners.GetNewPath(justForDiag: false);
            ObservableSourceStatusEnum lastParentStatus = lastParent.Status;

            System.Diagnostics.Debug.WriteLine($"Path = {bInfo.PropertyPath.Path}, NewPath = {strNewPath}, " +
                                               $"Terminal Node Status = {lastParentStatus}.");

            if (lastParentStatus.IsReadyOrWatching())
            {
                // Check to see if DataContext holds source property.
                // When a DataContext is set via a binding, in some cases,
                // bindings that rely on that DataContext may get set
                // before the binding that provides the correct DataContext is set.

                ObservableSource root = pathListeners[ROOT_INDEX];
                if (root.SourceKind == SourceKindEnum.FrameworkElement || root.SourceKind == SourceKindEnum.FrameworkContentElement)
                {
                    string firstChildPathElement = pathListeners[ROOT_INDEX + 1].PathElement;
                    if (!root.DoesChildExist(firstChildPathElement))
                    {
                        System.Diagnostics.Debug.WriteLine($"No Binding is being created. Data is present, but doesn't contain source property: {firstChildPathElement}.");
                        isCustom = false;
                        return(null);
                    }
                }

                // TODO: What about the original PropertyPath parameters?
                PropertyPath newPath = new PropertyPath(strNewPath);

                isCustom = lastParent.IsPropBagBased; // .IsPropBagBasedAndNoCustomTypeDescriptors;
                return(CreateBinding(bindingTarget, bInfo, sourceType, newPath, isCustom));
            }
            else
            {
                System.Diagnostics.Debug.Assert(pathListeners[0].IsListeningForNewDC, "There are no active listeners!");

                System.Diagnostics.Debug.WriteLine("No Binding is being created, not enough data.");
                isCustom = false;
                return(null);
            }
        }
Esempio n. 4
0
        private bool UpdateData_Dg(DataGridColumn dgc, string pathElement, string binderName)
        {
            if (SourceKind != SourceKindEnum.DataGridColumn)
            {
                throw new InvalidOperationException($"Cannot call {nameof(UpdateData_Dg)} " +
                                                    $"if the ObservableSource is not of SourceKind: {nameof(SourceKindEnum.DataGridColumn)}.");
            }

            System.Diagnostics.Debug.WriteLine($"Fetching DataGrid for a DataGridColumn for {pathElement}.");

            DataGrid dataGrid = LogicalTree.GetDataGridOwner(dgc);

            Type newType = dataGrid?.GetType();
            ObservableSourceStatusEnum newStatus = Status.SetReady(dataGrid != null);

            bool changed = UpdateData(dataGrid?.SelectedItems, newType, newStatus);

            return(changed);
        }
Esempio n. 5
0
        private void AddSubscriptions(object dc)
        {
            ObservableSourceStatusEnum workStatus = ObservableSourceStatusEnum.Undetermined;

            bool addedIt = false;

            if (dc is INotifyPCGen pcGen)
            {
                WeakEventManager <INotifyPCGen, PcGenEventArgs>
                .AddHandler(pcGen, "PropertyChangedWithGenVals", PCGenEvent_Handler);

                workStatus = ObservableSourceStatusEnum.IsWatchingProp;
                addedIt    = true;
            }

            if (dc is INotifyPropertyChanged pc)
            {
                WeakEventManager <INotifyPropertyChanged, PropertyChangedEventArgs>
                .AddHandler(pc, "PropertyChanged", OnPCEvent);

                workStatus = ObservableSourceStatusEnum.IsWatchingProp;
                addedIt    = true;
            }

            if (dc is INotifyCollectionChanged cc)
            {
                WeakEventManager <INotifyCollectionChanged, CollectionChangeEventArgs>
                .AddHandler(cc, "CollectionChanged", OnCCEvent);

                workStatus = workStatus.SetWatchingColl();
                addedIt    = true;
            }

            if (!addedIt)
            {
                string msg = "Cannot create subscriptions. Object does not implement INotifyPropertyChanged, " +
                             "nor does it implement INotifyCollectionChanged.";
                System.Diagnostics.Debug.WriteLine(msg);
                //throw new ApplicationException(msg);
            }
            Status = workStatus;
        }
Esempio n. 6
0
 public static bool IsNowReady(this ObservableSourceStatusEnum status, ObservableSourceStatusEnum oldStatus)
 {
     return(status.IsReadyOrWatching() && !oldStatus.IsReadyOrWatching());
 }
Esempio n. 7
0
 public static bool NoLongerReady(this ObservableSourceStatusEnum status, ObservableSourceStatusEnum oldStatus)
 {
     return(!status.IsReadyOrWatching() && oldStatus.IsReadyOrWatching());
 }
Esempio n. 8
0
 public static ObservableSourceStatusEnum SetWatchingColl(this ObservableSourceStatusEnum status)
 {
     return((status == ObservableSourceStatusEnum.IsWatchingProp) ?
            ObservableSourceStatusEnum.IsWatchingPropAndColl : ObservableSourceStatusEnum.IsWatchingColl);
 }
Esempio n. 9
0
 public static ObservableSourceStatusEnum SetReady(this ObservableSourceStatusEnum status, bool haveData)
 {
     return((haveData) ? ObservableSourceStatusEnum.Ready : ObservableSourceStatusEnum.NoType);
 }
Esempio n. 10
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);
        }
Esempio n. 11
0
        private bool UpdateWatcherAndData_Fe(DependencyObject targetObject, string pathElement,
                                             bool isTargetADc, string binderName)
        {
            if (SourceKind != SourceKindEnum.FrameworkElement && SourceKind != SourceKindEnum.FrameworkContentElement)
            {
                throw new InvalidOperationException($"Cannot call {nameof(UpdateWatcherAndData_Fe)} " +
                                                    $"if the ObservableSource does not have a SourceKind of {nameof(SourceKindEnum.FrameworkElement)} " +
                                                    $"or {nameof(SourceKindEnum.FrameworkContentElement)}.");
            }

            string fwElementName = LogicalTree.GetNameFromDepObject(targetObject);

            System.Diagnostics.Debug.WriteLine($"Fetching DataContext to use from: {fwElementName} for pathElement: {pathElement}.");

            this.IsTargetADc = isTargetADc;

            // If this binding sets a DataContext, watch the TargetObject's parent, otherwise watch the TargetObject for DataContext updates

            // TODO: May want to make sure that the value of Container is a DependencyObject.
            DependencyObject curContainer = (DependencyObject)Container;
            DependencyObject newContainer = isTargetADc ? LogicalTreeHelper.GetParent(targetObject) : targetObject;

            if (!object.ReferenceEquals(curContainer, newContainer))
            {
                SubscribeTo_FcOrFce(newContainer, DataContextChanged_Fe);
                Container = newContainer;
            }

            // Now see if we can find a data context.
            DependencyObject foundNode = LogicalTree.GetDataContext(targetObject, out bool foundIt,
                                                                    startWithParent: isTargetADc, inspectAncestors: true, stopOnNodeWithBoundDc: true);

            if (!foundIt)
            {
                bool changed = UpdateData(null, null, ObservableSourceStatusEnum.NoType);
                return(changed);
            }

            if (!object.ReferenceEquals(targetObject, foundNode))
            {
                string foundFwElementName = LogicalTree.GetNameFromDepObject(foundNode);
                System.Diagnostics.Debug.WriteLine($"Found DataContext to watch using an ancestor: {foundFwElementName} for pathElement: {pathElement}.");
            }
            else
            {
                System.Diagnostics.Debug.WriteLine($"Found DataContext to watch on the target object for pathElement: {pathElement}.");
            }

            DependencyObject foundNodeWithBoundDc = LogicalTree.GetDataContextWithBoundDc(targetObject,
                                                                                          out bool foundOneWithBoundDc, startWithParent: isTargetADc);

            if (foundOneWithBoundDc)
            {
                System.Diagnostics.Debug.WriteLine("Some parent has a DataContext that is set via a Binding Markup.");
            }

            if (foundNode is FrameworkElement fe)
            {
                Type newType = fe.DataContext?.GetType();
                ObservableSourceStatusEnum newStatus = Status.SetReady(fe.DataContext != null);

                bool changed = UpdateData(fe.DataContext, newType, newStatus);
                //if(newType.IsIListSource())
                //{
                //    changed = UpdateData(((IListSource)fe.DataContext).GetList(), newType, newStatus);
                //}
                //else
                //{
                //    changed = UpdateData(fe.DataContext, newType, newStatus);
                //}

                return(changed);
            }
            else if (foundNode is FrameworkContentElement fce)
            {
                Type newType = fce.DataContext?.GetType();
                ObservableSourceStatusEnum newStatus = Status.SetReady(fce.DataContext != null);
                bool changed = UpdateData(fce.DataContext, newType, newStatus);
                return(changed);
            }
            else
            {
                throw new ApplicationException($"Found node in {binderName}.ObservableSourceProvider was neither a FrameworkElement or a FrameworkContentElement.");
            }
        }
Esempio n. 12
0
        private bool GetDcFromFrameworkElement(object feOrFce, out object dc, out Type type, out ObservableSourceStatusEnum status)
        {
            bool found = LogicalTree.GetDcFromFrameworkElement(feOrFce, out dc, out type);

            status = Status.SetReady(dc != null);

            return(found);
        }