public static DependencyPropertyChangedListener Create(DependencyObject sourceElement, string propertyPath)
        //public static DependencyPropertyChangedListener Create(DependencyObject sourceElement, DependencyProperty property)
        {
            // check input
            if (sourceElement == null)
            {
                throw new ArgumentNullException("sourceElement");
            }
            if (string.IsNullOrWhiteSpace(propertyPath))
            {
                throw new ArgumentException("propertyPath is empty");
            }

            // create listener
            DependencyPropertyChangedListener listener = new DependencyPropertyChangedListener();

            // setup binding
            Binding binding = new Binding();

            binding.Source = sourceElement;
            binding.Mode   = BindingMode.OneWay;
            //binding.Path = new PropertyPath(property); // throws exception
            binding.Path = new PropertyPath(propertyPath);

            // create relay object
            RelayObject relay = new RelayObject(listener);

            // ...the listener holds a reference to the relay object in order that the GC does not collect it
            listener.RelayInstance = relay;

            // set binding
            BindingOperations.SetBinding(relay, RelayObject.ValueProperty, binding);

            return(listener);
        }
            private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                object      oldValue = (object)e.OldValue;
                object      newValue = (object)e.NewValue;
                RelayObject source   = (RelayObject)d;

                source.OnValueChanged(oldValue, newValue);
            }
        public void Detach()
        {
            if (this.RelayInstance != null)
            {
                // first: reset member to prevent further eventing of ValueChanged event.
                RelayObject temp = this.RelayInstance;
                this.RelayInstance = null;

                // second: clear the binding -> raises property changed event...
                temp.ClearValue(RelayObject.ValueProperty);
            }
        }
        /// <summary>
        /// Detaches the listener.
        /// </summary>
        public void Detach()
        {
            if (RelayInstance == null)
                return;

            var temp = RelayInstance;
            RelayInstance = null;

            temp.ClearValue(RelayObject.ValueProperty);
        }
        /// <summary>
        /// Creates a new instance of <see cref="DependencyPropertyChangedListener" />.
        /// </summary>
        /// <param name="sourceElement">The source element.</param>
        /// <param name="propertyPath">The property path.</param>
        /// <returns>The <see cref="DependencyPropertyChangedListener" />.</returns>
        /// <exception cref="System.ArgumentNullException">sourceElement</exception>
        /// <exception cref="System.ArgumentException">propertyPath is empty.</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="sourceElement" /> parameter is null.</exception>
        /// <exception cref="ArgumentException">The <paramref name="propertyPath" /> is null or whitespace.</exception>
        public static DependencyPropertyChangedListener Create(DependencyObject sourceElement, string propertyPath)
        {
            if (sourceElement == null)
                throw new ArgumentNullException("sourceElement");

            if (string.IsNullOrWhiteSpace(propertyPath))
                throw new ArgumentException("propertyPath is empty.");

            var listener = new DependencyPropertyChangedListener();
            var binding = new Binding(propertyPath) { Source = sourceElement, Mode = BindingMode.OneWay };
            var relay = new RelayObject(listener);
            listener.RelayInstance = relay;

            BindingOperations.SetBinding(relay, RelayObject.ValueProperty, binding);

            return listener;
        }