WPF CustomControl 无法绑定依赖关系 属性 两种查看模型的方式
WPF CustomControl unable to bind dependency property two way to view model
我创建了一个自定义控件,其依赖项 属性 绑定到视图模型 属性。
<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;
}
如果我将视图模型值设置为 "some value",我希望自定义控件使用该字符串并将其重置为 null。到目前为止这是有效的,但视图模型值未同步并且保持 "some value" 而不是 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);
}
如果您使用的是 4.5 之前的 .NET 版本,则需要改用 Dispatcher.BeginInvoke
方法。
我创建了一个自定义控件,其依赖项 属性 绑定到视图模型 属性。
<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;
}
如果我将视图模型值设置为 "some value",我希望自定义控件使用该字符串并将其重置为 null。到目前为止这是有效的,但视图模型值未同步并且保持 "some value" 而不是 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);
}
如果您使用的是 4.5 之前的 .NET 版本,则需要改用 Dispatcher.BeginInvoke
方法。