繁体   English   中英

更改附加属性的绑定源

[英]Change Source of Binding for attached property

如果我在附加属性中使用绑定扩展

<TextBlock local:MyBehavior.View="{Binding A}" /> <!-- or B -->

如何从该附加行为设置ViewModel的A (或B )属性的值?

我不明白:

  1. 附加属性使用哪种类型? Binding BindingBase BindingExpressionBase object
  2. 我应该立即设置值吗? 我要等什么吗? 我是否应该使用另一个依赖项属性来设置其值,然后绑定到SomeProperty并在设置DataContext让绑定完成该工作?

我的尝试失败 ,为方便起见,我在下面复制了它:

public class MyBehavior
{
    public static BindingBase GetView(DependencyObject obj) => (BindingBase)obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, BindingBase value) => obj.SetValue(ViewProperty, value);
    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(BindingBase), typeof(MyBehavior), new PropertyMetadata(null, (d, e) =>
        {
            var element = d as FrameworkElement;
            if (element == null)
                throw new ArgumentException("Only used with FrameworkElement");
            element.Loaded += (s, a) => GetView(element); // <<
        }));
}

我不确定在标记行设置绑定属性给定值的操作:

public class ViewModel
{
    public object A { get; set; }
    public object B { get; set; }
}

附加属性使用哪种类型?

与您在视图模型中定义source属性的类型相同,即object或附加属性应存储的任何类型的值。 类型取决于您打算在附加属性中存储的值的类型。

我应该立即设置值吗

注册依赖项属性时,可以为其指定默认值。 引用类型(例如object)的默认值通常为null

public class MyBehavior
{
    public static object GetView(DependencyObject obj) => obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, object value) => obj.SetValue(ViewProperty, value);

    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(object), typeof(MyBehavior), 
            new PropertyMetadata(/*default value: */ null, new PropertyChangedCallback(OnPropertyChanged)));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        //...
    }
}

当您绑定到视图模型时,依赖属性的值将像其他任何依赖属性一样自动设置,例如:

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    public object A { get; set; } = "value...";
}

MainWindow.xaml:

<TextBlock local:MyBehavior.View="{Binding A}" />

public class MyBehavior
{
    public static object GetView(DependencyObject obj) => obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, object value) => obj.SetValue(ViewProperty, value);

    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(object), typeof(MyBehavior), 
            new PropertyMetadata(/*default value: */ null, new PropertyChangedCallback(OnPropertyChanged)));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        object theValue = GetView(d);
        MessageBox.Show(theValue.ToString());
    }
}

如果希望将视图模型属性设置为附加属性的值,则应将绑定的模式设置为OneWayToSource

<TextBlock x:Name local:MyBehavior.View="{Binding A, Mode=OneWayToSource}" />

但是随后是更新视图模型的视图:

public MainWindow()
{
    InitializeComponent();
    DataContext = this;

    MyBehavior.SetView(txt, "new value...");
}

附加的依赖项属性本身就是可以在任何DependencyObject上设置的另一个依赖项属性。

编辑:

该解决方案仍然需要代码隐藏,我的意图是通过附加行为来消除它。 有想法吗? 注意element.Loaded(另请参阅我对@dymanoid的评论),想法是从附加行为中设置值,并且仅使用绑定来传递源(定义哪个属性A或B应该获得该值)。

然后,您可以简单地将附加属性设置为源属性的名称:

<TextBlock local:MyBehavior.View="A" />

...并使用反射在您附加的行为中设置此source属性的值:

public class MyBehavior
{
    public static object GetView(DependencyObject obj) => obj.GetValue(ViewProperty);
    public static void SetView(DependencyObject obj, object value) => obj.SetValue(ViewProperty, value);

    public static readonly DependencyProperty ViewProperty =
        DependencyProperty.RegisterAttached("View", typeof(object), typeof(MyBehavior), 
            new PropertyMetadata(/*default value: */ null, new PropertyChangedCallback(OnPropertyChanged)));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as FrameworkElement;
        if (element == null)
            throw new ArgumentException("Only used with FrameworkElement");
        element.Loaded += (s, a) => 
        {
            string propertyName = GetView(element).ToString();
            if(element.DataContext != null)
            {
                System.Reflection.PropertyInfo pi = element.DataContext.GetType().GetProperty(propertyName);
                pi.SetValue(element.DataContext, "new value...");
            }
        };
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM