Example #1
0
        protected virtual Binding CreateBinding(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType,
                                                PropertyPath newPath, bool isPropBagBased)
        {
            Binding result;

            if (isPropBagBased)
            {
                IValueConverter converter = GetConverter(bindingTarget, bInfo, sourceType,
                                                         newPath.Path, isPropBagBased, out object converterParameter);

                result = new Binding
                {
                    Path               = newPath,
                    Converter          = converter,
                    ConverterParameter = converterParameter,
                };
                ApplyStandardBindingParams(bInfo, ref result);
            }
            else
            {
                result = CreateDefaultBinding(bindingTarget, bInfo, sourceType, newPath);
            }

            return(result);
        }
Example #2
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);
            }
        }
Example #3
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);
        }
Example #4
0
        protected bool InitPathListeners(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType, OSCollection pathListeners)
        {
            DataSourceChangedEventArgs dsChangedEventArgs = new DataSourceChangedEventArgs(
                DataSourceChangeTypeEnum.Initializing, dataWasChanged: true);

            return(RefreshPathListeners(bindingTarget, bInfo, sourceType, pathListeners,
                                        dsChangedEventArgs, pathListeners[ROOT_INDEX]));
        }
Example #5
0
        //private string GetXmlnsPrefix(IXamlSchemaContextProvider schemaProvider, Type type)
        //{
        //    string ourName = type.Name;
        //    XamlSchemaContext context = schemaProvider.SchemaContext;

        //    IEnumerable<string> namespaces = context.GetAllXamlNamespaces();

        //    foreach(string ns in namespaces)
        //    {
        //        ICollection<XamlType> xamlTypes = context.GetAllXamlTypes(ns);

        //        foreach(XamlType xt in xamlTypes)
        //        {
        //            if(xt.IsMarkupExtension)
        //            {
        //                if(xt.Name == ourName)
        //                {
        //                    return ns;
        //                }
        //            }
        //        }
        //    }

        //    return null;
        //}

        #endregion

        public Binding GetBinding(BindingTarget bindingTarget)
        {
            MyBindingInfo bindingInfo = GatherBindingInfo(Path, Mode);

            MyBindingEngine mb = new MyBindingEngine(bindingInfo, SourceType, _bindingTarget, UseMultiBinding);

            return(mb.ProvideTheBindingDirectly());
        }
Example #6
0
        protected virtual object ProvideStandardBindingExp(IServiceProvider serviceProvider,
                                                           BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType)
        {
            Binding binding = CreateDefaultBinding(bindingTarget, bInfo, sourceType, bInfo.PropertyPath);

            return(binding);

            //BindingExpressionBase bExp = BuildBindingExpressionBase(serviceProvider, binding, isCustom: false);

            //return bExp;
        }
Example #7
0
        public MyBindingEngineBase(BindingTarget bindingTarget, MyBindingInfo bindingInfo, Type sourceType,
                                   bool useMultiBinding = true, string binderInstanceName = DEFAULT_BINDER_NAME)
        {
            BindingInfo   = bindingInfo;
            SourceType    = sourceType ?? throw new ArgumentNullException(nameof(sourceType));
            BindingTarget = bindingTarget ?? throw new ArgumentNullException(nameof(bindingTarget));

            UseMultiBinding = useMultiBinding;
            BinderName      = binderInstanceName;

            _dataSourceChangeListeners = null;
        }
Example #8
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);
            }
        }
Example #9
0
 public static ObservableSourceProvider GetSourceRoot(BindingTarget bindingTarget,
                                                      object source, string pathElement, string binderName)
 {
     if (source != null && GetSourceFromSource(source, pathElement, binderName, out ObservableSourceProvider osp))
     {
         return(osp);
     }
     else
     {
         GetDefaultSource(bindingTarget, pathElement, binderName, out osp);
         return(osp);
     }
 }
Example #10
0
        protected virtual MultiBindingExpression ProvideStandardMultiBindingExp(IServiceProvider serviceProvider,
                                                                                BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType)
        {
            // create wpf binding
            MyMultiValueConverter mValueConverter = new MyMultiValueConverter(BindingInfo.Mode);

            Binding binding = CreateDefaultBinding(bindingTarget, bInfo, sourceType, bInfo.PropertyPath);

            // This also sets the binding.
            MultiBindingExpression mExp = BuildMultiBindingExpression(serviceProvider, binding, isCustom: false);

            return(mExp);

            //// TODO: Should we SetTheBinding here? We need to test this.
            //return WrapBindingInMultiValueConverter(serviceProvider, binding, binding.Mode);
        }
Example #11
0
        //protected virtual void SetDefaultConverter()
        //{
        //    if (DefaultConverter == null)
        //    {
        //        if(DefaultConverterParameterBuilder != null)
        //        {
        //            throw new InvalidOperationException("The DefaultParameterBuilder has been given a value, but the DefaultConverter is unassigned.");
        //        }
        //        DefaultConverter = new Lazy<IValueConverter>(() => new PropValueConverter());
        //        DefaultConverterParameterBuilder = OurDefaultConverterParameterBuilder;
        //    }
        //}

        protected virtual IValueConverter GetConverter(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType,
                                                       string pathElement, bool isPropBagBased, out object converterParameter)
        {
            if (isPropBagBased)
            {
                if (bInfo.Converter != null)
                {
                    // Use the one specified in the MarkUp
                    converterParameter = bInfo.ConverterParameterBuilder(bindingTarget, bInfo, sourceType, pathElement);
                    return(bInfo.Converter);
                }
                else
                {
                    // Use the default for ItemsSource
                    if (bindingTarget.DependencyProperty.Name == "SelectedItem")
                    {
                        // If this is being used to supply a SelectedItem property.
                        converterParameter = null;
                        return(new SelectedItemConverter());
                    }
                    else
                    {
                        // Use the default converter provided by the caller or if no default provide our standard PropValueConverter.
                        converterParameter = DefaultConverterParameterBuilder(bindingTarget, bInfo, sourceType, pathElement);
                        return(DefaultConverter.Value);
                    }
                }
            }
            else
            {
                // If no converter specified and the target is SelectedItem,
                // use the SelectedItemConverter.
                if (bInfo.Converter == null && bindingTarget.DependencyProperty?.Name == "SelectedItem")
                {
                    converterParameter = null;
                    return(new SelectedItemConverter());
                }
                else
                {
                    // TODO: Check this. I beleive that the Microsoft Binder supplies a default converter.

                    // If no converter specified in the markup, no converter will be used.
                    converterParameter = bInfo.ConverterParameterBuilder(bindingTarget, bInfo, sourceType, pathElement);
                    return(bInfo.Converter);
                }
            }
        }
Example #12
0
        protected virtual Binding CreateDefaultBinding(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType,
                                                       PropertyPath newPath)
        {
            IValueConverter converter = GetConverter(bindingTarget, bInfo, sourceType,
                                                     newPath.Path, false, out object converterParameter);

            Binding binding = new Binding
            {
                Path               = newPath,
                Converter          = converter,
                ConverterParameter = converterParameter
                                     //ConverterCulture = bInfo.ConverterCulture,
            };

            ApplyStandardBindingParams(bInfo, ref binding);

            return(binding);
        }
Example #13
0
        private bool SetOurEnv(IServiceProvider serviceProvider, out BindingTarget bindingTarget)
        {
            bindingTarget = null;

            if (serviceProvider == null)
            {
                return(false);
            }

            IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

            if (provideValueTarget == null)
            {
                return(false);
            }

            IXamlSchemaContextProvider schemaProvider = serviceProvider.GetService(typeof(IXamlSchemaContextProvider)) as IXamlSchemaContextProvider;

            // Currently working on getting the xmlns prefix used for this instance.
            //string ns = GetXmlnsPrefix(schemaProvider, this.GetType());


            DependencyObject targetObject = provideValueTarget.TargetObject as DependencyObject;

            if (targetObject == null)
            {
                return(false);
            }

            if (provideValueTarget.TargetProperty is DependencyProperty dp)
            {
                bindingTarget = new BindingTarget(targetObject, dp);
                return(true);
            }
            else if (provideValueTarget.TargetProperty is PropertyInfo pi)
            {
                bindingTarget = new BindingTarget(targetObject, pi);
                return(true);
            }
            else
            {
                throw new InvalidOperationException("The target of the binding must be a DependencyProperty or a PropertyInfo.");
            }
        }
Example #14
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);
        }
Example #15
0
 private object GetConverterParameter(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType, string pathElement)
 {
     return bInfo.ConverterParameter;
 }
Example #16
0
 protected virtual object OurDefaultConverterParameterBuilder(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType,
                                                              string pathElement)
 {
     return(new TwoTypes(sourceType, bindingTarget.PropertyType));
 }
Example #17
0
        protected OSCollection PreparePathListeners(BindingTarget bindingTarget, MyBindingInfo bInfo, Type sourceType)
        {
            string[] nodes = GetPathComponents(bInfo.PropertyPath, out int compCount);

            return(new OSCollection(ROOT_PATH_ELEMENT, nodes, sourceType, BinderName));
        }
Example #18
0
 public MyBindingEngine(MyBindingInfo bindingInfo, Type sourceType, BindingTarget bindingTarget, bool useMultiBinding = true, string binderInstanceName = "pbb:Binder")
     : base(bindingTarget, bindingInfo, sourceType, useMultiBinding, binderInstanceName)
 {
 }