/// <summary> /// Tries to get a value from a <see cref="DependencyProperty"/> that is stored somewhere in the visual tree above this <see cref="DependencyObject"/>. /// If this is not available, it will register a <see cref="XAMLMarkupExtensions.Base.ParentChangedNotifier"/> on the last element. /// </summary> /// <typeparam name="T">The return type.</typeparam> /// <param name="target">The <see cref="DependencyObject"/>.</param> /// <param name="property">A <see cref="DependencyProperty"/> that will be read out.</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, DependencyProperty property, Action <DependencyObject> parentChangedAction, ParentNotifiers parentNotifiers) { return(target.GetValueOrRegisterParentNotifier(depObj => depObj.GetValueSync <T>(property), parentChangedAction, parentNotifiers)); }
/// <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); }