将Binding的Path属性绑定

4

是否可以将绑定的Path属性绑定到另一个属性?

我想实现以下代码:

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

所以我可以动态调整我的实际绑定所引用的属性。谢谢你的帮助,Jonny。

当您尝试此代码时,结果如何? - Ravi Y
路径不是一个 DependencyProperty。这会使绑定变得困难 ;) - Johannes Wanzek
5个回答

4

我自己解决了。

这是解决方案,希望能帮助到有和我一样问题的人。

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);
        }
    }
}

以下是XAML中的实现:

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

你好,Jonny


那个使用的是来自Blend的System.Windows.Interactivity吗? - Sean C.
是的。或者您可以使用“附加属性”,并在属性更改回调中应用该行为。 - Johannes Wanzek

2

正如其他帖子所提到的,你只能在依赖属性上设置绑定 - 而路径不是。根本原因是xaml是会被编译的源代码。在编译时,编译器不知道'CurrentPath'的值,并且无法编译。基本上,你想做的是运行时反射一个属性值 - 这可以使用你绑定的ViewModel中的另一个属性或使用转换器来完成。

ViewModel:

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

使用转换器:

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();
    }
}

当然,这些只适用于您想获取对象的简单属性 - 如果您想获取更复杂的内容,则反射代码将变得更加复杂。

除非您正在构建像属性网格这样的东西,或者因为某种原因您实际上想要自省运行在应用程序中的对象,否则我建议您重新审查设计,因为反射实际上只适用于少数情况。


嘿,谢谢你的回答。使用反射似乎不是最好的解决方案。我还处理复杂类型的EntityObjects,它们似乎也无法工作。无论如何,感谢你的回答,也许我会再回来看看这个解决方案 :) - Johannes Wanzek

1
也许您可以绑定到一个属性,该属性基于 switch 语句返回另一个属性,并绑定到该属性。更改“switch”属性,您就可以更改其他属性的输出。 只是不要忘记在绑定属性的 switch 属性中包含 NotifyPropertyChanged 的内容,否则您的视图将无法更新。 例如:
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;
        }
    }
}

嘿 Shifter,感谢你的回答。这正是我目前正在努力的方向。但为了通过“在文本框中键入”来反映任何属性的更改,它需要成为一个DependencyObject。如果是情况“A”,它会返回一个字符串,例如。而且如果是情况“B”,我需要传递一个实体对象。 - Johannes Wanzek
有可能“绑定到绑定”吗?这样,路径属性也可以在Codebehind或ViewModel中设置。 - Johannes Wanzek

1

Path不是一个依赖属性,因此绑定将无法工作。


哦,嘿,这就是我刚写的...我需要另一种解决方案。也许是转换器、选择器或某种动态资源... - Johannes Wanzek
聪明人想法相似...我会使用ViewModel,其中只需返回正确的文本。在ViewModel中,您返回相应的属性值。 - thumbmunkeys

0

我认为转换器可以帮助你。

例如:

第一个控件

Text="{Binding Path=CurrentPath}"

第二个控件

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

进制转换器

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
    }

我的转换器

 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;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接