[英]Change Source of Binding for attached property
如果我在附加属性中使用绑定扩展
<TextBlock local:MyBehavior.View="{Binding A}" /> <!-- or B -->
如何从该附加行为设置ViewModel的A
(或B
)属性的值?
我不明白:
Binding
? BindingBase
? BindingExpressionBase
? object
? 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.