private bool ProcessPath(IServiceProvider serviceProvider) { //////////////////////////////////////////////////////////////////////////////// // Validation. //////////////////////////////////////////////////////////////////////////////// if (string.IsNullOrWhiteSpace(this.path)) { binding = new Binding(); return(true); } //////////////////////////////////////////////////////////////////////////////// // Variables. //////////////////////////////////////////////////////////////////////////////// var parts = this.path.Split('.').Select(o => o.Trim()).ToArray(); var partIndex = 0; RelativeSource oRelativeSource = null; Object oSource = null; string elementName = null; //////////////////////////////////////////////////////////////////////////////// // Determine and process the 'entry' binding type. //////////////////////////////////////////////////////////////////////////////// if (parts[0].StartsWith("#")) { elementName = parts[0].Substring(1); partIndex++; } else if (parts[0].ToLower() == "ancestors" || parts[0].ToLower() == "ancestor") { if (parts.Length < 2) { throw new Exception("Invalid path, expected exactly 2 identifiers ancestors.#Type#.[Path] (e.g. Ancestors.DataGrid, Ancestors.DataGrid.SelectedItem, Ancestors.DataGrid.SelectedItem.Text)"); } var sType = parts[1]; var oType = (Type) new System.Windows.Markup.TypeExtension(sType).ProvideValue(serviceProvider); if (oType == null) { throw new Exception("Could not find type: " + sType); } oRelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, oType, 1); partIndex += 2; } else if (parts[0].ToLower() == "template" || parts[0].ToLower() == "templateparent" || parts[0].ToLower() == "templatedparent" || parts[0].ToLower() == "templated") { oRelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent); partIndex++; } else if (parts[0].ToLower() == "thiswindow" || parts[0].ToLower() == "window") { oRelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Window), 1); partIndex++; } else if (parts[0].ToLower() == "root") { IRootObjectProvider rootProvider = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider; oSource = (rootProvider != null) ? rootProvider.RootObject : null; partIndex++; } else if (parts[0].ToLower() == "this") { oRelativeSource = new RelativeSource(RelativeSourceMode.Self); partIndex++; } //////////////////////////////////////////////////////////////////////////////// // Advanced path. //////////////////////////////////////////////////////////////////////////////// var partsForPathString = parts.Skip(partIndex); IValueConverter callMethodConverter = null; //////////////////////////////////////////////////////////////////////////////// // Special processing for binding to Methods and Commands. //////////////////////////////////////////////////////////////////////////////// if (partsForPathString.Any()) { var sLastPartForPathString = partsForPathString.Last(); if (sLastPartForPathString.EndsWith("()")) { // Retrieve target info. IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; DependencyObject targetObject = null; object targetProperty = null; if (provideValueTarget != null) { targetObject = provideValueTarget.TargetObject as DependencyObject; targetProperty = provideValueTarget.TargetProperty; } if (targetProperty != null && targetProperty is DependencyProperty) { partsForPathString = partsForPathString.Take(partsForPathString.Count() - 1); methodName = sLastPartForPathString.Remove(sLastPartForPathString.Length - 2); callMethodConverter = new CallMethodValueConverter(methodName); } else if (targetProperty != null && targetProperty.GetType().FullName.Equals("System.Reflection.RuntimeEventInfo")) // else if (targetProperty != null && targetProperty is System.Reflection.RuntimeEventInfo) // RuntimeEventInfo is locked away where I cant even compare against the type directly. { InternalBindToMethod(oSource, sLastPartForPathString, targetObject, targetProperty); // Return false indicating Parsing is done and we don't want to do any actual XAML binding. // We've already bound the proxy directly to the event object. return(false); } } } //////////////////////////////////////////////////////////////////////////////// // Compute the 'Path' //////////////////////////////////////////////////////////////////////////////// var bindingPath = string.Join(".", partsForPathString.ToArray()); //////////////////////////////////////////////////////////////////////////////// // Build the Binding element. //////////////////////////////////////////////////////////////////////////////// if (string.IsNullOrWhiteSpace(bindingPath)) { binding = new Binding(); } else { binding = new Binding(bindingPath); } if (elementName != null) { binding.ElementName = elementName; } if (oRelativeSource != null) { binding.RelativeSource = oRelativeSource; } if (oSource != null) { binding.Source = oSource; } if (callMethodConverter != null) { binding.Converter = callMethodConverter; } else if (this.converter != null) { binding.Converter = this.converter; } //////////////////////////////////////////////////////////////////////////////// // Build - Propagate Properties. // - It turns out that property propagation validation is problematic. We were trying to // determine if the user was trying to overwrite a property that previous processing has // already explicitly set. In this situation we wanted to throw error/exception. // - However, this is a problem in that several of Binding's properties are of value type and/or // get default values, so it is non trivial to determine if the above processing has set the value // or if it is just a default value; add to this that that default value can be different // based on which XAML property type is being bound to. // - So to make this work completely, we'd have to depend solely on the processing the above // does; i.e. keep track of which binding properties the processing does. //////////////////////////////////////////////////////////////////////////////// ValidatePropagateProperty(binding.AsyncState, AsyncState); // ValidatePropagateProperty(binding.BindsDirectlyToSource , BindsDirectlyToSource); ValidatePropagateProperty(binding.ConverterCulture, ConverterCulture); ValidatePropagateProperty(binding.ConverterParameter, ConverterParameter); ValidatePropagateProperty(binding.ElementName, ElementName); // ValidatePropagateProperty(binding.IsAsync , IsAsync); // ValidatePropagateProperty(binding.Mode , Mode); // ValidatePropagateProperty(binding.NotifyOnSourceUpdated , NotifyOnSourceUpdated); // ValidatePropagateProperty(binding.NotifyOnTargetUpdated , NotifyOnTargetUpdated); // ValidatePropagateProperty(binding.NotifyOnValidationError , NotifyOnValidationError); //ValidatePropagateProperty(binding.RelativeSource , RelativeSource); //ValidatePropagateProperty(binding.Source , Source); //ValidatePropagateProperty(binding.Path , Path); ValidatePropagateProperty(binding.UpdateSourceExceptionFilter, UpdateSourceExceptionFilter); // ValidatePropagateProperty(binding.UpdateSourceTrigger , UpdateSourceTrigger); // ValidatePropagateProperty(binding.ValidatesOnDataErrors , ValidatesOnDataErrors); // ValidatePropagateProperty(binding.ValidatesOnExceptions , ValidatesOnExceptions); // ValidatePropagateProperty(binding.ValidatesOnNotifyDataErrors , ValidatesOnNotifyDataErrors); //ValidatePropagateProperty(binding.ValidationRules { get); } , ValidationRules { get); } ValidatePropagateProperty(binding.XPath, XPath); if (AsyncState.HasValue()) { binding.AsyncState = AsyncState; } if (BindsDirectlyToSource.HasValue) { binding.BindsDirectlyToSource = BindsDirectlyToSource.Value; } if (ConverterCulture.HasValue()) { binding.ConverterCulture = ConverterCulture; } if (ConverterParameter.HasValue()) { binding.ConverterParameter = ConverterParameter; } if (ElementName.HasValue()) { binding.ElementName = ElementName; } if (IsAsync.HasValue) { binding.IsAsync = IsAsync.Value; } if (Mode.HasValue) { binding.Mode = Mode.Value; } if (NotifyOnSourceUpdated.HasValue) { binding.NotifyOnSourceUpdated = NotifyOnSourceUpdated.Value; } if (NotifyOnTargetUpdated.HasValue) { binding.NotifyOnTargetUpdated = NotifyOnTargetUpdated.Value; } if (NotifyOnValidationError.HasValue) { binding.NotifyOnValidationError = NotifyOnValidationError.Value; } //binding.RelativeSource = RelativeSource; //binding.Source = Source; //binding.Path = Path; if (UpdateSourceExceptionFilter.HasValue()) { binding.UpdateSourceExceptionFilter = UpdateSourceExceptionFilter; } if (UpdateSourceTrigger.HasValue) { binding.UpdateSourceTrigger = UpdateSourceTrigger.Value; } if (ValidatesOnDataErrors.HasValue) { binding.ValidatesOnDataErrors = ValidatesOnDataErrors.Value; } if (ValidatesOnExceptions.HasValue) { binding.ValidatesOnExceptions = ValidatesOnExceptions.Value; } if (ValidatesOnNotifyDataErrors.HasValue) { binding.ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors.Value; } if (Delay.HasValue) { binding.Delay = Delay.Value; } //binding.ValidationRules = ValidationRules { get; } if (XPath.HasValue()) { binding.XPath = XPath; } //////////////////////////////////////////////////////////////////////////////// // Binding property set successfully. //////////////////////////////////////////////////////////////////////////////// return(true); }