private void RegisterParentNotifier() { parentChangedNotifier = new ParentChangedNotifier(this, () => { parentChangedNotifier.Dispose(); parentChangedNotifier = null; var targetObject = this.Parent; if (targetObject != null) { var properties = GetDependencyProperties(targetObject); foreach (var p in properties) { if (targetObject.GetValue(p) == this) { targetInfo = new TargetInfo(targetObject, p, p.PropertyType, -1); Binding binding = new Binding("Content"); binding.Source = this; binding.Converter = this.Converter; binding.ConverterParameter = this.ConverterParameter; binding.Mode = BindingMode.OneWay; BindingOperations.SetBinding(targetObject, p, binding); UpdateNewValue(); } } } }); }
/// <summary> /// Tries to get a value that is stored somewhere in the visual tree above this <see cref="DependencyObject"/>. /// <para>If this is not available, it will register a <see cref="ParentChangedNotifier"/> on the last element.</para> /// </summary> /// <typeparam name="T">The return type.</typeparam> /// <param name="target">The <see cref="DependencyObject"/>.</param> /// <param name="GetFunction">The function that gets the value from a <see cref="DependencyObject"/>.</param> /// <param name="ParentChangedAction">The notification action on the change event of the Parent property.</param> /// <param name="parentNotifiers">A dictionary of already registered notifiers.</param> /// <returns>The value, if possible.</returns> public static T GetValueOrRegisterParentNotifier <T>( this DependencyObject target, Func <DependencyObject, T> GetFunction, Action <DependencyObject> ParentChangedAction, ParentNotifiers parentNotifiers) { var ret = default(T); if (target == null) { return(ret); } var depObj = target; var weakTarget = new WeakReference(target); while (ret == null) { // Try to get the value using the provided GetFunction. ret = GetFunction(depObj); if (ret != null && parentNotifiers.ContainsKey(target)) { parentNotifiers.Remove(target); } // Try to get the parent using the visual tree helper. This may fail on some occations. #if !SILVERLIGHT if (!(depObj is Visual) && !(depObj is Visual3D) && !(depObj is FrameworkContentElement)) { break; } if (depObj is Window) { break; } #endif DependencyObject depObjParent = null; #if !SILVERLIGHT if (depObj is FrameworkContentElement) { depObjParent = ((FrameworkContentElement)depObj).Parent; } else { try { depObjParent = depObj.GetParent(false); } catch { depObjParent = null; } } #endif if (depObjParent == null) { try { depObjParent = depObj.GetParent(true); } catch { break; } } // If this failed, try again using the Parent property (sometimes this is not covered by the VisualTreeHelper class :-P. if (depObjParent == null && depObj is FrameworkElement) { depObjParent = ((FrameworkElement)depObj).Parent; } if (ret == null && depObjParent == null) { // Try to establish a notification on changes of the Parent property of dp. if (depObj is FrameworkElement && !parentNotifiers.ContainsKey(target)) { var pcn = new ParentChangedNotifier((FrameworkElement)depObj, () => { var localTarget = (DependencyObject)weakTarget.Target; if (!weakTarget.IsAlive) { return; } // Call the action... ParentChangedAction(localTarget); // ...and remove the notifier - it will probably not be used again. if (parentNotifiers.ContainsKey(localTarget)) { parentNotifiers.Remove(localTarget); } }); parentNotifiers.Add(target, pcn); } break; } // Assign the parent to the current DependencyObject and start the next iteration. depObj = depObjParent; } return(ret); }
/// <summary> /// Adds the key-value-pair. /// </summary> /// <param name="target">The target key object.</param> /// <param name="parentChangedNotifier">The notifier.</param> public void Add(DependencyObject target, ParentChangedNotifier parentChangedNotifier) { _inner.Add(new WeakReference <DependencyObject>(target), new WeakReference <ParentChangedNotifier>(parentChangedNotifier)); }