C# 绑定。路径绑定

C# 绑定。路径绑定,c#,wpf,mvvm,binding,C#,Wpf,Mvvm,Binding,我怎样才能做到以下几点 <CheckBox Content="{Binding Caption}"> <CheckBox.IsChecked> <Binding Path="{Binding PropertyName}" Source="{Binding Source}" /> </CheckBox.IsChecked> </CheckBox> 想法是通过属性为绑定提供

我怎样才能做到以下几点

<CheckBox Content="{Binding Caption}">
    <CheckBox.IsChecked>
        <Binding Path="{Binding PropertyName}"
                 Source="{Binding Source}" />
    </CheckBox.IsChecked>
</CheckBox>
想法是通过属性为绑定提供
路径
(在设计时未知)

public class CheckBoxCustomBindingBehavior : Behavior<CheckBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
    }

    public object Source
    {
        get
        {
            return (object)GetValue(SourceProperty);
        }
        set
        {
            SetValue(SourceProperty, value);
        }
    }

    // Using a DependencyProperty as the backing store for Source.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(object), typeof(CheckBoxCustomBindingBehavior), new PropertyMetadata(null, OnSourceChanged));

    private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as CheckBoxCustomBindingBehavior).ModifyBinding();
    }

    public string Path
    {
        get
        {
            return (string)GetValue(PathProperty);
        }
        set
        {
            SetValue(PathProperty, value);
        }
    }

    // Using a DependencyProperty as the backing store for Path.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PathProperty =
        DependencyProperty.Register("Path", typeof(string), typeof(CheckBoxCustomBindingBehavior), new PropertyMetadata(string.Empty, OnPathChanged));

    private static void OnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as CheckBoxCustomBindingBehavior).ModifyBinding();
    }

    private void ModifyBinding()
    {
        var source = Source ?? AssociatedObject.DataContext;
        if (source != null && !string.IsNullOrEmpty(Path))
        {
            Binding b = new Binding(Path);
            b.Source = source;
            AssociatedObject.SetBinding(CheckBox.IsCheckedProperty, b);
        }
    }
}

当前,在
中抛出异常,我将使用行为。下面的行为将获取源和路径,并相应地更新IsChecked属性的绑定。您可以扩展此功能以满足您的需要。目前,这仅限于IsChecked属性,您可以编写通用代码来支持所有属性

public class CheckBoxCustomBindingBehavior : Behavior<CheckBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
    }

    public object Source
    {
        get
        {
            return (object)GetValue(SourceProperty);
        }
        set
        {
            SetValue(SourceProperty, value);
        }
    }

    // Using a DependencyProperty as the backing store for Source.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(object), typeof(CheckBoxCustomBindingBehavior), new PropertyMetadata(null, OnSourceChanged));

    private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as CheckBoxCustomBindingBehavior).ModifyBinding();
    }

    public string Path
    {
        get
        {
            return (string)GetValue(PathProperty);
        }
        set
        {
            SetValue(PathProperty, value);
        }
    }

    // Using a DependencyProperty as the backing store for Path.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PathProperty =
        DependencyProperty.Register("Path", typeof(string), typeof(CheckBoxCustomBindingBehavior), new PropertyMetadata(string.Empty, OnPathChanged));

    private static void OnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as CheckBoxCustomBindingBehavior).ModifyBinding();
    }

    private void ModifyBinding()
    {
        var source = Source ?? AssociatedObject.DataContext;
        if (source != null && !string.IsNullOrEmpty(Path))
        {
            Binding b = new Binding(Path);
            b.Source = source;
            AssociatedObject.SetBinding(CheckBox.IsCheckedProperty, b);
        }
    }
}
公共类CheckBoxCustomBindingBehavior:Behavior
{
受保护的覆盖无效附加()
{
base.onatached();
}
公共对象源
{
得到
{
返回(对象)GetValue(SourceProperty);
}
设置
{
SetValue(SourceProperty,value);
}
}
//使用DependencyProperty作为源的备份存储。这将启用动画、样式、绑定等。。。
公共静态只读DependencyProperty SourceProperty=
Register(“Source”、typeof(object)、typeof(CheckBoxCustomBindingBehavior)、newpropertyMetadata(null、OnSourceChanged));
资源上的私有静态无效已更改(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
(d为CheckBoxCustomBindingBehavior).ModifyBinding();
}
公共字符串路径
{
得到
{
返回(字符串)GetValue(路径属性);
}
设置
{
SetValue(路径属性,值);
}
}
//使用DependencyProperty作为路径的后备存储。这将启用动画、样式、绑定等。。。
公共静态只读DependencyProperty PathProperty=
Register(“Path”、typeof(string)、typeof(CheckBoxCustomBindingBehavior)、newpropertyMetadata(string.Empty、OnPathChanged));
私有静态void OnPathChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
(d为CheckBoxCustomBindingBehavior).ModifyBinding();
}
私有void ModifyBinding()
{
var source=source??AssociatedObject.DataContext;
if(source!=null&!string.IsNullOrEmpty(Path))
{
绑定b=新绑定(路径);
b、 来源=来源;
AssociatedObject.SetBinding(CheckBox.IsCheckedProperty,b);
}
}
}
以及Xaml的使用

 <CheckBox xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
        <i:Interaction.Behaviors>
            <local:CheckBoxCustomBindingBehavior Path="{Binding SelectedPath}" Source="{Binding}" />
        </i:Interaction.Behaviors>
    </CheckBox>

SelectedPath来自model,这就是我存储属性名的地方


注意:您将需要交互式程序集。

编译时必须知道源属性的名称,才能在XAML中设置绑定:

<CheckBox Content="{Binding Caption}">
    <CheckBox.IsChecked>
        <Binding Path="Source.Property" />
    </CheckBox.IsChecked>
</CheckBox>

但是,在纯XAML中无法做到这一点。请记住,XAML是一种标记语言。

在看到@WPFUser one之后,回答有点晚,但它支持任何属性,我个人不喜欢混合依赖项:

public class DynamicBinding
{
    public static object GetSource(DependencyObject obj) => (object)obj.GetValue(SourceProperty);
    public static void SetSource(DependencyObject obj, object value) => obj.SetValue(SourceProperty, value);
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.RegisterAttached("Source", typeof(object), typeof(DynamicBinding), new PropertyMetadata(null, (d, e) => SetBinding(d)));

    public static string GetProperty(DependencyObject obj) => (string)obj.GetValue(PropertyProperty);
    public static void SetProperty(DependencyObject obj, string value) => obj.SetValue(PropertyProperty, value);
    public static readonly DependencyProperty PropertyProperty =
        DependencyProperty.RegisterAttached("Property", typeof(string), typeof(DynamicBinding), new PropertyMetadata(null, (d, e) => SetBinding(d)));

    public static string GetTarget(DependencyObject obj) => (string)obj.GetValue(TargetProperty);
    public static void SetTarget(DependencyObject obj, string value) => obj.SetValue(TargetProperty, value);
    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.RegisterAttached("Target", typeof(string), typeof(DynamicBinding), new PropertyMetadata(null, (d, e) => SetBinding(d)));

    static void SetBinding(DependencyObject obj)
    {
        var source = GetSource(obj);
        var property = GetProperty(obj);
        var target = GetTarget(obj);
        // only if all required attached properties values are set
        if (source == null || property == null || target == null)
            return;
        BindingOperations.SetBinding(obj, DependencyPropertyDescriptor.FromName(target, obj.GetType(), obj.GetType()).DependencyProperty,
            new Binding(property) { Source = source });
    }
}
用法是:

<CheckBox Content="{Binding Caption}"
          local:DynamicBinding.Property="{Binding PropertyName}"
          local:DynamicBinding.Source="{Binding Source}"
          local:DynamicBinding.Target="IsChecked" />

Target
可以是控件的任何依赖属性。它是作为一个普通字符串给出的,我不确定如何改进它,以便在输入它时获得intellisense帮助


ToDo:如果更改了
目标
(它将反映对
属性
所做的更改),则不会删除绑定,不支持多个动态绑定(例如,对控件的不同属性)。

回答不错,它将支持MVVM。只是澄清一下;在视图的代码隐藏中创建与视图模型属性的绑定不会破坏MVVM模式。MVVM是关于分离关注点,而不是从视图中删除代码。代码隐藏类与XAML标记是同一视图的一部分。@mm8,您的答案是可以的,我一直在使用它作为解决方案。然而,当您开始广泛使用数据模板时(我的问题的原因),这段代码会产生巨大的问题。将其隐藏到可重用行为中可以让您纯粹在xaml(例如资源字典)中定义模板。行为是更好的选择,因为它允许以动态方式在一个元素上绑定多个属性。DP DynamicBinding.Target只能设置一次。但考虑到附加属性的想法,下一个想法将是创建这些属性。然后,
IsChecked
属性由唯一命名的附加属性
dynamicBindingtSourceChecked
DynamicBindingPropertyIsChecked
dynamicBindingTargetChecked
处理。
public class DynamicBinding
{
    public static object GetSource(DependencyObject obj) => (object)obj.GetValue(SourceProperty);
    public static void SetSource(DependencyObject obj, object value) => obj.SetValue(SourceProperty, value);
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.RegisterAttached("Source", typeof(object), typeof(DynamicBinding), new PropertyMetadata(null, (d, e) => SetBinding(d)));

    public static string GetProperty(DependencyObject obj) => (string)obj.GetValue(PropertyProperty);
    public static void SetProperty(DependencyObject obj, string value) => obj.SetValue(PropertyProperty, value);
    public static readonly DependencyProperty PropertyProperty =
        DependencyProperty.RegisterAttached("Property", typeof(string), typeof(DynamicBinding), new PropertyMetadata(null, (d, e) => SetBinding(d)));

    public static string GetTarget(DependencyObject obj) => (string)obj.GetValue(TargetProperty);
    public static void SetTarget(DependencyObject obj, string value) => obj.SetValue(TargetProperty, value);
    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.RegisterAttached("Target", typeof(string), typeof(DynamicBinding), new PropertyMetadata(null, (d, e) => SetBinding(d)));

    static void SetBinding(DependencyObject obj)
    {
        var source = GetSource(obj);
        var property = GetProperty(obj);
        var target = GetTarget(obj);
        // only if all required attached properties values are set
        if (source == null || property == null || target == null)
            return;
        BindingOperations.SetBinding(obj, DependencyPropertyDescriptor.FromName(target, obj.GetType(), obj.GetType()).DependencyProperty,
            new Binding(property) { Source = source });
    }
}
<CheckBox Content="{Binding Caption}"
          local:DynamicBinding.Property="{Binding PropertyName}"
          local:DynamicBinding.Source="{Binding Source}"
          local:DynamicBinding.Target="IsChecked" />