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); }
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); } } }
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); } }
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); } }
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)); } }
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); }
/// <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); }