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 方法。