/// <summary> /// Implements the IDisposable.Dispose function. /// </summary> public void Dispose() { EndpointReachedEvent.RemoveListener(rootObjectHashCode, this); targetObjects.Clear(); }
/// <summary> /// The ProvideValue method of the <see cref="MarkupExtension"/> base class. /// </summary> /// <param name="serviceProvider">A service provider.</param> /// <returns>The value of the extension, or this if something gone wrong (needed for Templates).</returns> public sealed override object ProvideValue(IServiceProvider serviceProvider) { // If the service provider is null, return this if (serviceProvider == null) { return(this); } OnServiceProviderChanged(serviceProvider); // Try to cast the passed serviceProvider to a IProvideValueTarget IProvideValueTarget service = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; // If the cast fails, return this if (service == null) { return(this); } #if NET35 rootObjectHashCode = 0; #else // Try to cast the passed serviceProvider to a IRootObjectProvider and if the cast fails return null IRootObjectProvider rootObject = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider; if (rootObject == null) { rootObjectHashCode = 0; } else { rootObjectHashCode = rootObject.RootObject.GetHashCode(); // We only sign up once to the Window Closed event to clear the listeners list of root object. if (rootObject.RootObject != null && !EndpointReachedEvent.ContainsRootObjectHash(rootObjectHashCode)) { if (rootObject.RootObject is Window window) { window.Closed += delegate(object sender, EventArgs args) { EndpointReachedEvent.ClearListenersForRootObject(rootObjectHashCode); }; } else if (rootObject.RootObject is FrameworkElement frameworkElement) { void frameworkElementUnloadedHandler(object sender, RoutedEventArgs args) { frameworkElement.Unloaded -= frameworkElementUnloadedHandler; EndpointReachedEvent.ClearListenersForRootObject(rootObjectHashCode); } frameworkElement.Unloaded += frameworkElementUnloadedHandler; } } } #endif // Declare a target object and property TargetInfo endPoint = null; object targetObject = service.TargetObject; object targetProperty = service.TargetProperty; int targetPropertyIndex = -1; Type targetPropertyType = null; // First, check if the service provider is of type SimpleProvideValueServiceProvider // -> If yes, get the target property type and index. // Check if the service.TargetProperty is a DependencyProperty or a PropertyInfo and set the type info if (serviceProvider is SimpleProvideValueServiceProvider) { targetPropertyType = ((SimpleProvideValueServiceProvider)serviceProvider).TargetPropertyType; targetPropertyIndex = ((SimpleProvideValueServiceProvider)serviceProvider).TargetPropertyIndex; endPoint = ((SimpleProvideValueServiceProvider)serviceProvider).EndPoint; } else { if (targetProperty is PropertyInfo) { PropertyInfo pi = (PropertyInfo)targetProperty; targetPropertyType = pi.PropertyType; // Kick out indexers. if (pi.GetIndexParameters().Any()) { throw new InvalidOperationException("Indexers are not supported!"); } } else if (targetProperty is DependencyProperty) { DependencyProperty dp = (DependencyProperty)targetProperty; targetPropertyType = dp.PropertyType; } else { return(this); } } // If the service.TargetObject is System.Windows.SharedDp (= not a DependencyObject and not a PropertyInfo), we return "this". // The SharedDp will call this instance later again. if (!(targetObject is DependencyObject) && !(targetProperty is PropertyInfo)) { return(this); } // If the target object is a DictionaryEntry we presumably are facing a resource scenario. // We will be called again later with the proper target. if (targetObject is DictionaryEntry) { return(null); } // Search for the target in the target object list WeakReference wr = (from kvp in targetObjects where kvp.Key.Target == targetObject select kvp.Key).FirstOrDefault(); if (wr == null) { // If it's the first object, call the appropriate action if (targetObjects.Count == 0) { if (OnFirstTarget != null) { OnFirstTarget(); } } // Add the target as a WeakReference to the target object list wr = new WeakReference(targetObject); targetObjects.Add(wr, new Dictionary <Tuple <object, int>, Type>()); // Add this extension to the ObjectDependencyManager to ensure the lifetime along with the target object ObjectDependencyManager.AddObjectDependency(wr, this); } // Finally, add the target prop and info to the list of this WeakReference Tuple <object, int> tuple = new Tuple <object, int>(targetProperty, targetPropertyIndex); if (!targetObjects[wr].ContainsKey(tuple)) { targetObjects[wr].Add(tuple, targetPropertyType); } // Sign up to the EndpointReachedEvent only if the markup extension wants to do so. EndpointReachedEvent.AddListener(rootObjectHashCode, this); // Create the target info TargetInfo info = new TargetInfo(targetObject, targetProperty, targetPropertyType, targetPropertyIndex); // Return the result of FormatOutput object result = null; if (info.IsEndpoint) { var args = new EndpointReachedEventArgs(info); EndpointReachedEvent.Invoke(rootObjectHashCode, this, args); result = args.EndpointValue; } else { result = FormatOutput(endPoint, info); } // Check type if (typeof(IList).IsAssignableFrom(targetPropertyType)) { return(result); } else if ((result != null) && targetPropertyType.IsAssignableFrom(result.GetType())) { return(result); } // Finally, if nothing was there, return null or default if (targetPropertyType.IsValueType) { return(Activator.CreateInstance(targetPropertyType)); } else { return(null); } }