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。有什么办法吗?为什么双向绑定不能这样工作呢?

谢谢。

WPF CustomControl无法以两种方式绑定依赖属性来查看模型

这一行

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