internal PropertyPathWalker(string path, bool isDatacontextBound) { _path = path; _isDataContextBound = isDatacontextBound; if (_isDataContextBound) { _firstNode = new DependencyPropertyNode(FrameworkElement.DataContextProperty); } ParsePath(_path, out IPropertyPathNode head, out IPropertyPathNode tail); if (_firstNode == null) { _firstNode = head ?? new StandardPropertyPathNode(); } else { _firstNode.Next = head; } FinalNode = tail ?? _firstNode; FinalNode.Listen(this); }
void IPropertyPathNodeListener.ValueChanged(IPropertyPathNode node) { ValueInternal = node.Value; IPropertyPathWalkerListener listener = _listener; if (listener != null) { listener.ValueChanged(); } }
void IPropertyPathNodeListener.IsBrokenChanged(IPropertyPathNode node) { ValueInternal = node.Value; var listener = _listener; if (listener != null) { listener.IsBrokenChanged(); } }
private void OnSourcePropertyChanged(object sender, PropertyChangedEventArgs e) { if ((e.PropertyName == _propertyName || string.IsNullOrEmpty(e.PropertyName)) && (_prop != null || _field != null)) { UpdateValue(); IPropertyPathNode next = Next; if (next != null) { next.SetSource(Value); } } }
private void ParsePath(string path, out IPropertyPathNode head, out IPropertyPathNode tail) { head = null; tail = null; var parser = new PropertyPathParser(path); PropertyNodeType type; while ((type = parser.Step(out string typeName, out string propertyName, out string index)) != PropertyNodeType.None) { IPropertyPathNode node; switch (type) { case PropertyNodeType.AttachedProperty: case PropertyNodeType.Property: node = new StandardPropertyPathNode(typeName, propertyName); break; case PropertyNodeType.Indexed: node = new IndexedPropertyPathNode(index); break; default: throw new InvalidOperationException(); } if (head == null) { head = tail = node; continue; } tail.Next = node; tail = node; } }
/// <summary> /// This method is used to check whether the value is Valid if needed. /// </summary> /// <param name="initialValue"></param> internal void CheckInitialValueValidity(object initialValue) { if (ParentBinding.ValidatesOnExceptions && ParentBinding.ValidatesOnLoad) { if (!_propertyPathWalker.IsPathBroken) { INTERNAL_ForceValidateOnNextSetValue = false; try { IPropertyPathNode node = _propertyPathWalker.FinalNode; node.SetValue(node.Value); //we set the source property to its own value to check whether it causes an exception, in which case the value is not valid. } catch (Exception e) //todo: put the content of this catch in a method which will be called here and in UpdateSourceObject (OR put the whole try/catch in the method and put the Value to set as parameter). { //We get the new Error (which is the innermost exception as far as I know): Exception currentException = e; #if OPENSILVER if (true) // Note: "InnerException" is only supported in the Simulator as of July 27, 2017. #elif BRIDGE if (CSHTML5.Interop.IsRunningInTheSimulator) // Note: "InnerException" is only supported in the Simulator as of July 27, 2017. #endif { while (currentException.InnerException != null) { currentException = currentException.InnerException; } } Validation.MarkInvalid(this, new ValidationError(this) { Exception = currentException, ErrorContent = currentException.Message }); } } } }
internal PropertyPathWalker(string path, bool isDatacontextBound) { Path = path; StandardPropertyPathNode lastNode; IsDataContextBound = isDatacontextBound; if (path == null || path == ".") { //bindsDirectlyToSource set to true means that the binding is directly made to the source (--> there is no path) lastNode = new StandardPropertyPathNode(); //what to put in there ? FirstNode = lastNode; FinalNode = lastNode; } else { PropertyNodeType type; var parser = new PropertyPathParser(path); string typeName; string propertyName; int index; //IPropertyPathNode node; while ((type = parser.Step(out typeName, out propertyName, out index)) != PropertyNodeType.None) { //we make node advance (when it is not the first step, otherwise it stays at null) //node = FinalNode; //var isViewProperty = false; //boolean isViewProperty = CollectionViewProperties.Any (prop => prop.Name == propertyName); // static readonly PropertyInfo[] CollectionViewProperties = typeof (ICollectionView).GetProperties (); switch (type) { case PropertyNodeType.AttachedProperty: case PropertyNodeType.Property: if (FinalNode == null) { FinalNode = new StandardPropertyPathNode(typeName, propertyName); } else { FinalNode.Next = new StandardPropertyPathNode(typeName, propertyName); } break; case PropertyNodeType.Indexed: throw new NotImplementedException("Indexed properties are not supported yet."); //todo: when we will handle the indexed properties, uncomment the following //node.Next = new IndexedPropertyPathNode(index); break; default: break; } if (FirstNode == null) { FirstNode = FinalNode; } if (FinalNode.Next != null) { FinalNode = FinalNode.Next; } } } this.FinalNode.Listen(this); }
internal void UpdateSourceObject(object value) { if (_propertyPathWalker.IsPathBroken) { return; } IPropertyPathNode node = _propertyPathWalker.FinalNode; bool oldIsUpdating = IsUpdating; object convertedValue = value; Type expectedType = node.Type; try { if (expectedType != null && ParentBinding.Converter != null) { #if MIGRATION convertedValue = ParentBinding.Converter.ConvertBack(value, expectedType, ParentBinding.ConverterParameter, ParentBinding.ConverterCulture); #else convertedValue = ParentBinding.Converter.ConvertBack(value, expectedType, ParentBinding.ConverterParameter, ParentBinding.ConverterLanguage); #endif if (convertedValue == DependencyProperty.UnsetValue) { return; } } if (!IsValueValidForSourceUpdate(convertedValue, expectedType)) { IsUpdating = true; #if MIGRATION convertedValue = DynamicConverter.Convert(convertedValue, expectedType, null, ParentBinding.ConverterCulture); #else convertedValue = DynamicConverter.Convert(convertedValue, expectedType, null, ParentBinding.ConverterLanguage); #endif if (convertedValue == DependencyProperty.UnsetValue) { return; } } node.SetValue(convertedValue); Validation.ClearInvalid(this); } catch (Exception e) { //If we have ValidatesOnExceptions set to true, we display a popup with the error close to the element. if (ParentBinding.ValidatesOnExceptions) { //We get the new Error (which is the innermost exception as far as I know): Exception currentException = e; while (currentException.InnerException != null) { currentException = currentException.InnerException; } Validation.MarkInvalid(this, new ValidationError(this) { Exception = currentException, ErrorContent = currentException.Message }); } } finally { IsUpdating = oldIsUpdating; } }