/// <summary> /// Returns a data descriptor for the access to a collection-like instance /// <paramref name="maybeCollection"/> with an <paramref name="index"/>. /// </summary> /// <param name="maybeCollection">Instance which may be collection-like, like an /// <see cref="IList{T}"/>, <see cref="ICollection{T}"/> or <see cref="IEnumerable{T}"/>. /// The returned data descriptor will allow to read the value, and for an /// <see cref="IList{T}"/> it will also be writeable.</param> /// <param name="index">Index to access the collection-like instance.</param> /// <param name="result">Returns the data descriptor for the access to the /// <paramref name="index"/>th entry in <paramref name="maybeCollection"/>.</param> /// <returns><c>true</c>, if <paramref name="maybeCollection"/> is a collection-like /// instance and could be accessed by the specified <paramref name="index"/>, else /// <c>false</c>.</returns> public static bool GetEnumerationEntryByIndex(object maybeCollection, int index, out IDataDescriptor result) { if (maybeCollection is IList) { result = new IndexerDataDescriptor(maybeCollection, new object[] { index }); return(true); } if (maybeCollection is IEnumerable) { int i = 0; foreach (object o in (IEnumerable)maybeCollection) { if (i++ == index) { result = new ValueDataDescriptor(o); return(true); } } throw new XamlBindingException("Index '{0}' is out of range (# elements={1})", index, i); } result = null; return(false); }
/// <summary> /// Returns the information if the specified <paramref name="other"/> descriptor /// references the same <see cref="Value"/>. /// </summary> /// <param name="other">Other descriptor whose <see cref="Value"/> should be compared.</param> public bool ValueEquals(ValueDataDescriptor other) { return(_value == null ? (other == null) : _value.Equals(other._value)); }
/// <summary> /// Returns a data descriptor for the access to a collection-like instance /// <paramref name="maybeCollection"/> with an <paramref name="index"/>. /// </summary> /// <param name="maybeCollection">Instance which may be collection-like, like an /// <see cref="IList{T}"/>, <see cref="ICollection{T}"/> or <see cref="IEnumerable{T}"/>. /// The returned data descriptor will allow to read the value, and for an /// <see cref="IList{T}"/> it will also be writeable.</param> /// <param name="index">Index to access the collection-like instance.</param> /// <param name="result">Returns the data descriptor for the access to the /// <paramref name="index"/>th entry in <paramref name="maybeCollection"/>.</param> /// <returns><c>true</c>, if <paramref name="maybeCollection"/> is a collection-like /// instance and could be accessed by the specified <paramref name="index"/>, else /// <c>false</c>.</returns> public static bool GetEnumerationEntryByIndex(object maybeCollection, int index, out IDataDescriptor result) { if (maybeCollection is IList) { result = new IndexerDataDescriptor(maybeCollection, new object[] { index }); return true; } if (maybeCollection is IEnumerable) { int i = 0; foreach (object o in (IEnumerable)maybeCollection) { if (i++ == index) { result = new ValueDataDescriptor(o); return true; } } throw new XamlBindingException("Index '{0}' is out of range (# elements={1})", index, i); } result = null; return false; }
/// <summary> /// Returns the information if the specified <paramref name="other"/> descriptor /// references the same <see cref="Value"/>. /// </summary> /// <param name="other">Other descriptor whose <see cref="Value"/> should be compared.</param> public bool ValueEquals(ValueDataDescriptor other) { return _value == null ? (other == null) : _value.Equals(other._value); }
/// <summary> /// Does the lookup for our binding source data. This includes evaluation of our source /// properties and the lookup for the data context. /// </summary> /// <remarks> /// During the lookup, change handlers will be attached to all relevant properties /// on the search path to the binding source. If one of the properties changes, /// this binding will re-evaluate. /// </remarks> /// <param name="result">Resulting source descriptor, if it could be resolved.</param> /// <returns><c>true</c>, if the binding source could be found and evaluated, /// <c>false</c> if it could not be resolved (yet).</returns> protected bool GetSourceDataDescriptor(out IDataDescriptor result) { ResetChangeHandlerAttachments(); result = null; try { switch (_typeOfSource) { case SourceType.DataContext: return FindDataContext(out result); case SourceType.SourceProperty: #if DEBUG_BINDINGS if (Source == null) DebugOutput("GetSourceDataDescriptor doesn't have a Source", Source); #endif result = new DependencyPropertyDataDescriptor(this, "Source", _sourceProperty); return true; case SourceType.RelativeSource: DependencyObject current = _contextObject; if (current == null) return false; switch (RelativeSource.Mode) { case RelativeSourceMode.Self: result = new ValueDataDescriptor(current); return true; case RelativeSourceMode.TemplatedParent: while (current != null) { DependencyObject last = current; FindParent(last, out current, FindParentMode.HybridPreferVisualTree); UIElement lastUIElement = last as UIElement; if (lastUIElement != null) { AttachToSourcePathProperty(lastUIElement.TemplateNameScopeProperty); if (lastUIElement.IsTemplateControlRoot) { result = new ValueDataDescriptor(current); return true; } } } #if DEBUG_BINDINGS DebugOutput("GetSourceDataDescriptor didn't find TemplateParent"); #endif return false; case RelativeSourceMode.FindAncestor: if (FindAncestor(current, out current, FindParentMode.HybridPreferVisualTree, RelativeSource.AncestorLevel, RelativeSource.AncestorType)) { result = new ValueDataDescriptor(current); return true; } return false; //case RelativeSourceMode.PreviousData: // // TODO: implement this // throw new NotImplementedException(RelativeSourceMode.PreviousData.ToString()); default: // Should never occur. If so, we have forgotten to handle a RelativeSourceMode throw new NotImplementedException( string.Format("RelativeSourceMode '{0}' is not implemented", RelativeSource.Mode)); } case SourceType.ElementName: INameScope nameScope; if (!FindNameScope(out nameScope)) return false; object obj = nameScope.FindName(ElementName) as UIElement; if (obj == null) { #if DEBUG_BINDINGS DebugOutput("GetSourceDataDescriptor didn't find object with name '{0}'", ElementName); #endif return false; } result = new ValueDataDescriptor(obj); return true; default: // Should never occur. If so, we have forgotten to handle a SourceType throw new NotImplementedException( string.Format("SourceType '{0}' is not implemented", _typeOfSource)); } } finally { AttachToSource(result); IObservable observable = result == null ? null : result.Value as IObservable; if (observable != null) AttachToSourceObservable(observable); } }
protected IDataDescriptor GetDataDescriptor(UIElement element) { string targetName = Storyboard.GetTargetName(this); object targetObject = null; if (targetName == null) targetObject = element; else { INameScope ns = element.FindNameScope(); if (ns != null) targetObject = ns.FindName(targetName); if (targetObject == null) targetObject = element.FindElement(new NameMatcher(targetName)); if (targetObject == null) return null; } try { IDataDescriptor result = new ValueDataDescriptor(targetObject); if (_propertyExpression != null && _propertyExpression.Evaluate(result, out result)) return result; } catch (XamlBindingException e) { ServiceRegistration.Get<ILogger>().Warn("PropertyAnimationTimeline: Error evaluating expression '{0}' on target object '{1}'", e, _propertyExpression, targetObject); } return null; }