如果我在附加属性中使用绑定扩展
<TextBlock local:MyBehavior.View="{Binding A}" /> <!-- or B -->
如何从该附加行为中设置ViewModel的A
(或B
)属性值?
我不明白:
Binding
? BindingBase
? BindingExpressionBase
? object
?SomeProperty
并让绑定在设置DataContext
后完成工作吗?我失败的尝试是here,为方便起见,我将其复制到下面:
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; }
}
答案 0 :(得分:1)
附属物使用哪种类型?
与您在视图模型中定义源属性的类型相同,即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...");
}
附加的依赖属性isself只是可以在任何DependencyObject上设置的另一个依赖属性。
修改强>
此解决方案仍然需要代码隐藏,我的意图是通过附加行为消除它。想法?注意element.Loaded(另见我对@dymanoid的评论),想法是设置附加行为的值,只使用绑定来传递源(定义哪个属性,A或B,应该得到该值)。
然后,您只需将附加属性设置为源属性的名称:
<TextBlock local:MyBehavior.View="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)
{
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...");
}
};
}
}