更改附加属性的绑定源 [英] Change Source of Binding for attached property

查看:56
本文介绍了更改附加属性的绑定源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

If I use binding extension in attached property

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

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

How can set value of A (or B) property of ViewModel from that attached behavior?

我不明白:

  1. 哪种类型用于附加财产?绑定? BindingBase ? BindingExpressionBase ? object ?
  2. 我应该立即设置值吗?我要等待一些事件吗?我应该使用另一个依赖项属性来设置它的值,然后绑定到 SomeProperty 并在设置了 DataContext 后让绑定完成该工作吗?
  1. Which type to use for attached property? Binding? BindingBase? BindingExpressionBase? object?
  2. Shall I set the value immediately? Shall I wait for some event? Shall I use another dependency property to set it's value, then bind to SomeProperty and let binding do the job once DataContext is set?

我的失败尝试是此处,为方便起见,我将其复制到以下位置:

My failed attempt is here, for convenience I copied it below:

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

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

I am not sure what to do at marked line to set value of given by binding property:

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

推荐答案

哪种类型用于附加属性?

Which type to use for attached property?

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

The same type as you have defined the source property in the view model with, i.e. object or whatever type of value that the attached property should store. The type depends on the type of value you intend to store in the attached property.

我应立即设置值

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

You can specify a default value for a dependency property when you register it. The default value for a reference type such as object is typically 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)
    {
        //...
    }
}

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

The value of the dependency property will be set automatically when you bind to the view model just like any other dependency property, e.g.:

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 :

If you want to be able to set the view model property to the value of your attached property you should set the Mode of the binding to OneWayToSource:

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

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

But then it is the view that updates the view model:

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

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

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

The attached dependency property isself is just another dependency property that can be set on any DependencyObject.

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

This solution still require code-behind, my intent to eliminate it with attached behavior. Ideas? Notice element.Loaded (see also my comment to @dymanoid), idea was to set the value from attached behavior and only use binding to pass source (defining which property, A or B, should get that value).

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

Then you could simply set your attached property to the name of the source property:

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

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

...and use reflection to set the value of this source property in your attached behaviour:

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

这篇关于更改附加属性的绑定源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆