Binding the Path Property of a Binding

前端 未结 5 1784
广开言路
广开言路 2020-12-11 09:24

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=CurrentPat         


        
相关标签:
5条回答
  • 2020-12-11 09:46

    I think converter can helps your. Expample

    First control

    Text="{Binding Path=CurrentPath}"
    

    Second control

    Text="{Binding Path=CurrentPath, Convertor={converters:MyConvertor}}"
    

    Base converter

    public abstract class ConvertorBase<T> : MarkupExtension, IValueConverter
        where T : class, new()
        {
                public abstract object Convert(object value, Type targetType, object parameter,
                CultureInfo culture);
    
                public virtual object ConvertBack(object value, Type targetType, object parameter,
                CultureInfo culture)
            {
                throw new NotImplementedException();
            }
    
            #region MarkupExtension members
    
            public override object ProvideValue(IServiceProvider serviceProvider)
            {
                if (_converter == null)
                    _converter = new T();
                return _converter;
            }
    
            private static T _converter = null;
    
            #endregion
        }
    

    MyConverter

     public class MyConverter: ConvertorBase<MyConverter>
        {
            public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return (string)value.Equals("blabla") ? "Yes" : "No"; // here return necessary parametr
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                return null;
            }
        }
    
    0 讨论(0)
  • 2020-12-11 09:58

    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

    0 讨论(0)
  • 2020-12-11 10:03

    Path is not a dependency property, therefore the binding will not work.

    0 讨论(0)
  • 2020-12-11 10:04

    Perhaps you could bind to a property that returns another property based on a switch statement and bind to that. Change the 'switch' property and you change the output of the other property. Just don't forget to include your NotifyPropertyChanged stuff in the switch property for the bound property otherwise your view will not update. e.g.

    private int _mySwitch;
    
    //Set this to determine what the other property will return.
    public int SwitchProperty
    {
        get { return _mySwitch; }
        set
        {
            _mySwitch = value;
            NotifyPropertyChanged("MySwitchableProperty");
        }
    }
    public String PropertyA { get; set; }
    public String PropertyB { get; set; }
    
    //Bind to this property
    public String MySwitchableProperty
    {
        get
        {
            switch (SwitchProperty)
            {
                case 1:
                    return PropertyA;
                    break;
                case 2:
                    return PropertyB;
                    break;
                default :
                    return String.Empty;
                    break;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-11 10:10

    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.

    0 讨论(0)
提交回复
热议问题