WPF CustomControl无法以两种方式绑定依赖属性来查看模型
本文关键字:属性 依赖 模型 绑定 方式 CustomControl 两种 WPF | 更新日期: 2023-09-27 18:15:50
我已经创建了一个自定义控件,它的依赖属性绑定到一个视图模型属性。
<wpf1:CustomTextBox StringProperty="{Binding StringValue}" />
视图模型如下图所示
public class ViewModel : INotifyPropertyChanged
{
public string StringValue
{
get { return m_stringValue; }
set
{
m_stringValue = value;
OnPropertyChanged("StringValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string m_stringValue;
}
DataContext在
后面的代码中设置public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = ViewModel = new ViewModel();
}
public ViewModel ViewModel { get; set; }
}
默认情况下,依赖属性的绑定模式是双向的
public static readonly DependencyProperty StringPropertyProperty =
DependencyProperty.Register(
"StringProperty",
typeof(string),
typeof(CustomTextBox),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
PropertyChangedCallback = PropertyChangedCallback
});
现在我有问题了,当视图模型属性StringValue被改变时,自定义控件被通知,但是当我改变依赖属性的值时,视图模型的值没有改变。
private static void PropertyChangedCallback(DependencyObject dO,
DependencyPropertyChangedEventArgs e)
{
var textBox = (CustomTextBox) dO;
if (textBox.StringProperty == null)
return;
DoSomething(textBox.StringProperty)
textBox.StringProperty = null;
}
如果我将视图模型值设置为"某些值",我希望自定义控件使用该字符串并将其重置为null。到目前为止,这是有效的,但是视图模型值没有同步,并且保持"一些值"而不是null。有什么办法吗?为什么双向绑定不能这样工作呢?
谢谢。
这一行
textBox.StringProperty = null;
删除之前定义的绑定(<wpf1:CustomTextBox StringProperty="{Binding StringValue}" />
)
尝试使用
textBox.SetCurrentValue(StringPropertyProperty, null);
您的代码没有像预期的那样工作的原因是,您正在为StringProperty
分配新值,同时仍然处理先前对该属性的更改。我真的不知道这背后的机制(可能是某种机制,旨在防止潜在的无限递归调用?),但我100%确定这是罪魁祸首。
为了解决你的问题,推迟新的值赋值,直到控件从你的处理程序返回,这可以很容易地通过使用与你的控件相关的Dispatcher
来实现:
private static void PropertyChangedCallback(DependencyObject dO,
DependencyPropertyChangedEventArgs e)
{
var textBox = (CustomTextBox) dO;
if (textBox.StringProperty == null)
return;
DoSomething(textBox.StringProperty)
//following lambda will be queued for execution rather than executed immediately
//and is guaranteed to be executed after this handler has finished
textBox.Dispatcher.InvokeAsync(() => textBox.StringProperty = null);
}
如果你使用的是。net 4.5之前的版本,你将需要使用Dispatcher.BeginInvoke
方法。