Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding the Path Property of a Binding

is it possible to bind the Path property of a binding to another property?

I want to realize this code:

Text="{Binding Path={Binding Path=CurrentPath}}"

So I can adjust dynamically to which Property my actual binding is refering.

Thanks for your Help Jonny

like image 270
Johannes Wanzek Avatar asked Feb 19 '23 09:02

Johannes Wanzek


2 Answers

I worked it out on myself.

Heres the solution, I hope it might help anyone got the same problem like me.

public class CustomBindingBehavior : Behavior<FrameworkElement>
{
    public bool IsBinding
    {
        get
        {
            return (bool)GetValue(IsBindingProperty);

        }
        set
        {
            SetValue(IsBindingProperty, value);
        }
    }

    public string PropertyPath
    {
        get
        {
            return (string)GetValue(PropertyPathProperty);

        }
        set
        {
            SetValue(PropertyPathProperty, value);
        }
    }

    public static DependencyProperty
        PropertyPathProperty = DependencyProperty.Register("PropertyPath", typeof(string),
                        typeof(CustomBindingBehavior), null);

    public static DependencyProperty
        IsBindingProperty = DependencyProperty.Register("IsBinding", typeof(bool),
                        typeof(CustomBindingBehavior), null);

    protected override void OnAttached()
    {
        if (AssociatedObject is TextBlock)
        {
            var tb = AssociatedObject as TextBlock;
            tb.Loaded += new RoutedEventHandler(tb_Loaded);
        }
    }

    private void tb_Loaded(object sender, RoutedEventArgs e)
    {
        AddBinding(sender as TextBlock, TextBlock.TextProperty);
    }

    private void AddBinding(DependencyObject targetObj, DependencyProperty targetProp)
    {
        if (IsBinding)
        {
            Binding binding = new Binding();
            binding.Path = new PropertyPath(this.PropertyPath, null);

            BindingOperations.SetBinding(targetObj, targetProp, binding);
        }
        else
        {
            targetObj.SetValue(targetProp, this.PropertyPath);
        }
    }
}

And heres the implementation in XAML:

<TextBlock >
                <i:Interaction.Behaviors>
                    <behaviors:CustomBindingBehavior PropertyPath="{Binding Path=HeaderPropertyBinding}" IsBinding="{Binding Path=HeaderIsBinding}" />
                </i:Interaction.Behaviors>
            </TextBlock>

Greetings Jonny

like image 173
Johannes Wanzek Avatar answered Feb 26 '23 21:02

Johannes Wanzek


As other posters have mentioned, you can only set a binding on a dependency property - which path is not. The underlying reason is that xaml is source code that gets compiled. At compile time the compiler has no idea what the value of 'CurrentPath' is, and would not be able to compile. Essentially what you are looking to do is runtime reflection of a property value - which could be done using another property in the ViewModel you are binding to, or using a converter.

ViewModel:

public string CurrentValue
{
    get
    {
         var property = this.GetType().GetProperty(CurrentPath);
         return property.GetValue(this, null);
    }
} 

Using a converter:

public class CurrentPathToValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var viewModel = (ViewModel)value;
        var property = viewModel.GetType().GetProperty(viewModel.CurrentPath);
        var currentValue = property.GetValue(viewModel, null);
        return currentValue;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Of couse these only work if you want to get a simple property of the object - if you want to get something more complex your reflection code is going to get a lot more complex.

Unless you are building something like a property grid, or for some other reason you actually want to introspect the objects running in your application, I would suggest you revisit your design, as reflection is really only suited to a few situations.

like image 28
Brian Flynn Avatar answered Feb 26 '23 20:02

Brian Flynn