=> target.DataContextChanged -= DatacontextTarget_DataContextChanged; // free up event handlers. /// <summary> /// Called whenever the datacontext of one of the inner source binding changed. /// </summary> /// <param name="sender">A framework element for which the property changed.</param> /// <param name="e">Information about the datacontext changed event.</param> private void DatacontextTarget_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { if (TargetObject == sender && TargetProperty != null) { ToggleBinding(BindingHelpers.GetBindingSource(innerBinding, TargetObject, out bool _, out bool _)); } else if (sender is FrameworkElement casted) { casted.DataContextChanged -= DatacontextTarget_DataContextChanged; } }
protected override void OnTargetLoaded(FrameworkElement target) => Initialize(); // retry class initialization at loaded. /// <summary> /// Prepares this class to filter data based on resolved (or unresolved source). /// </summary> private void Initialize() { if (initialized) { return; } // Find source value here if not provided: var source = BindingHelpers.GetBindingSource(innerBinding, TargetObject, out bool resolved, out bool _); if (resolved) { Initialize(source); } }
/// <summary> /// Called whenever the datacontext of target object changed. /// </summary> /// <param name="sender">A framework element for which the property changed.</param> /// <param name="e">Information about the datacontext changed event.</param> private void DatacontextTarget_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { if (TargetObject == sender && TargetProperty != null) { if (bindingWatcher != null) { bindingWatcherDescriptor.RemoveValueChanged(bindingWatcher, BindingWatcher_SourcePropertyChanged); bindingWatcher.Dispose(); } bindingWatcher = new DependencyPropertyWatcher <object>(BindingHelpers.GetBindingSource(InnerBinding, TargetObject, out bool _, out bool _), InnerBinding.Path); bindingWatcherDescriptor = bindingWatcherDescriptor = DependencyPropertyDescriptor.FromProperty(DependencyPropertyWatcher <object> .ValueProperty, typeof(DependencyPropertyWatcher <object>)); bindingWatcherDescriptor.AddValueChanged(bindingWatcher, BindingWatcher_SourcePropertyChanged); } else if (sender is FrameworkElement casted) { casted.DataContextChanged -= DatacontextTarget_DataContextChanged; } }
/// <summary> /// Resolves path binding and prepares the inner custom binding with resolved path value. /// </summary> /// <param name="serviceProvider">Service provider given by the framework.</param> /// <returns>True if successfully prepared path binding, false if cannot resolve its value.</returns> private bool ResolveBoundPathBinding(IServiceProvider serviceProvider = null) { if (PathValueBinding == null) { return(false); } // If source is not already resolved: if (boundPathSource == null) { // Try to get the source of value for the path value binding using base mechanisms: boundPathSource = serviceProvider != null?BindingHelpers.GetBindingSource(PathValueBinding, serviceProvider, out bool source_is_resolved, out bool source_is_datacontext) : BindingHelpers.GetBindingSource(PathValueBinding, TargetObject, out source_is_resolved, out source_is_datacontext); if (!source_is_resolved || boundPathSource == null) { return(false); } // If source is datacontext then track it for future changes: if (source_is_datacontext) { (TargetObject as FrameworkElement).DataContextChanged += TargetObject_DataContextChanged; } } // Try to resolve path binding value on the source: var value = BindingHelpers.ResolvePathValue(boundPathSource, PathValueBinding.Path); // If not given a proper property path format: if (!(value is string) && !(value is PropertyPath)) { StopTrackingPathBindingUpdates(); // as we did not resolved binding, stop tracking changes on current bind if any. return(false); } // Update bound path binding by getting a copy of the precedent value: if (!providing_value) { boundPathBinding = boundPathBinding?.Clone(); if (boundPathBinding == null) { return(false); } } // Build new inner binding path based on resolved value + OverridePath property: if (value is string as_string) { if (!OverridePath && Path != null) { boundPathBinding.Path = new PropertyPath(Path.Path + "." + as_string); // TODO: path parameters? } else { boundPathBinding.Path = new PropertyPath(as_string); } } else if (value is PropertyPath asPropertyPath) { if (!OverridePath && Path != null) { boundPathBinding.Path = new PropertyPath(Path.Path + "." + asPropertyPath.Path, asPropertyPath.PathParameters); } else { boundPathBinding.Path = asPropertyPath; } } // As we resolved binding, track any further changes: StartTrackingPathBindingUpdates(); return(true); }