我创建了一个自定义控件,其依赖项属性绑定到视图模型属性。
<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;
}
如果我将视图模型值设置为&#34;某些值&#34;我希望自定义控件使用该字符串并将其重置为null。到目前为止,这是有效的,但视图模型值不同步,并保持&#34;某些价值&#34;而不是null。任何想法如何做到这一点?为什么双向绑定不起作用?
感谢。
答案 0 :(得分:2)
这一行
<wpf1:CustomTextBox StringProperty="{Binding StringValue}" />
删除之前定义的绑定(textBox.SetCurrentValue(StringPropertyProperty, null);
)
尝试使用
{{1}}
答案 1 :(得分:0)
您编码的原因无法按预期运行的原因是您在处理之前对该属性的更改时,正在为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);
}
如果您使用4.5之前的.NET版本,则需要使用Dispatcher.BeginInvoke
方法。