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);
        }
 internal RelayObject(DependencyPropertyChangedListener listener)
 {
     _listener = listener;
 }